自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Rust 1.80后如何使用延遲初始化模式?

開發(fā) 前端
與lazy_static和once_cell這兩種crate相比,標(biāo)準(zhǔn)庫提供的延遲初始化類型的一大優(yōu)點是不需要任何額外的依賴項。盡管這兩個crate本身只有幾個依賴項,但這仍然意味著你的項目將有更多的依賴項,并且需要更多的編譯時間。

在應(yīng)用程序開始時最常見的事情之一是初始化各種資源。這可以是應(yīng)用程序配置、日志服務(wù)或某些數(shù)據(jù)庫連接。然而,并非所有這些都需要在應(yīng)用開始時就準(zhǔn)備好,因為這可能會導(dǎo)致啟動緩慢。

這就需要在使用資源的時候再進行初始化,延遲初始化模式可以幫助我們推遲資源的初始化。如果資源根本不使用,也可以完全跳過初始化。

在Rust的舊版本中,其標(biāo)準(zhǔn)庫不支持這種延遲初始化。在生態(tài)系統(tǒng)中有幾個流行的crate通常用于此功能,例如lazy_static和once_cell。從Rust 1.80開始,這些crate提供的許多功能現(xiàn)在可以在標(biāo)準(zhǔn)庫中使用,并且可以用來代替這兩個crate。

在這篇文章中,我們將介紹什么是延遲初始化模式,lazy_static和once_cell如何提供延遲初始化的功能,如何使用標(biāo)準(zhǔn)庫進行延遲初始化,標(biāo)準(zhǔn)庫與lazy_static和once_cell之間的比較。

延遲初始化模式

考慮一個示例,我們有一個不經(jīng)常使用的API接口,需要從磁盤讀取和解析一個大文件。

我們可以在應(yīng)用程序開始時執(zhí)行讀取和解析,但是,這可能會阻止服務(wù)器在解析完成之前提供服務(wù)。還有一種情況是,這個特定的API接口根本沒有被調(diào)用,因此用于加載文件的資源是沒有用的。

另一個例子是,如果應(yīng)用程序使用一些內(nèi)存DB,如sqlite或redis。但是,實際上并非應(yīng)用程序的所有調(diào)用都需要數(shù)據(jù)庫。在這種情況下,將DB加載到內(nèi)存中并每次維護連接開銷是沒必要的。

我們可以將這些資源的初始化推遲到需要的時候,在第一次使用時初始化它們,并保留它們以供以后使用,這種模式被稱為延遲初始化模式。

然而,這在Rust中出現(xiàn)了一個小問題,我們必須將延遲初始化的資源作為參數(shù)傳遞給每個函數(shù),或者將其設(shè)置為靜態(tài)全局的,并在運行時使用unsafe的Rust代碼對其進行初始化。

為了避免這種情況,像lazy_static或once_cell這樣的crate為不安全的操作提供了安全的封裝,我們可以使用它們在代碼中安全地使用延遲初始化的值。

lazy_static和once_cell如何提供延遲初始化

lazy_static提供了一個宏來編寫靜態(tài)變量的初始化代碼,并且在運行時第一次使用時初始化變量。一般語法是:

use lazy_static::lazy_static;
lazy_static!{
  static ref VAR : TYPE = {initialization code}
}

例如,將日志級別設(shè)置為靜態(tài)變量,如下所示:

use lazy_static::lazy_static;

lazy_static! {
    static ref LOG_LEVEL: String = get_log_level();
}

fn get_log_level() -> String {
    match std::env::var("LOG_LEVEL") {
        Ok(s) => s,
        Err(_) => "WARN".to_string(),
    }
}

fn main() {
    println!("{}", *LOG_LEVEL);
}

lazy_static!宏定義在運行時使用get_log_level函數(shù)來設(shè)置日志級別。

雖然這很簡單,但它也有一些自己的問題。我們必須使用靜態(tài)ref,這不是一個有效的Rust語法,我們需要取消對LOG_LEVEL的引用,以便在println語句中使用。

我們可以使用once_cellcrate做同樣的事情:

use once_cell::sync::OnceCell;

static LOG_LEVEL: OnceCell<String> = OnceCell::new();

fn get_log_level() -> String {
    match std::env::var("LOG_LEVEL") {
        Ok(s) => s,
        Err(_) => "WARN".to_string(),
    }
}

fn main() {
    let log_level = LOG_LEVEL.get_or_init(get_log_level);
    println!("{}", log_level);
}

在這里,我們沒有在聲明中指定代碼,而是在需要獲取值時使用了get_or_init方法。

如果值未初始化,則使用給定函數(shù)初始化該值,否則將返回現(xiàn)有值。因為我們直接獲取值,所以不需要任何額外的解引用操作。

雖然這兩種方法各有優(yōu)缺點,但是需要在依賴項中再添加一個外部crate。Rust 1.80后的標(biāo)準(zhǔn)庫提供了延遲初始化的類型,我們就可以直接使用這些類型,從而減少依賴項的數(shù)量。

使用標(biāo)準(zhǔn)庫進行延遲初始化

在Rust 1.80后,類似lazy_static和once_cell的延遲初始化類型已經(jīng)在Rust標(biāo)準(zhǔn)庫中穩(wěn)定下來了。我們可以使用它們代替任何外部crate來實現(xiàn)類似的功能。

標(biāo)準(zhǔn)庫中的OnceLock類型可以類似于once_cellcrate的OnceCell類型使用:

use std::sync::OnceLock;

static LOG_LEVEL: OnceLock<String> = OnceLock::new();

fn get_log_level() -> String {
    match std::env::var("LOG_LEVEL") {
        Ok(s) => s,
        Err(_) => "WARN".to_string(),
    }
}

fn main() {
    let log_level = LOG_LEVEL.get_or_init(get_log_level);
    println!("{}", log_level);
}

與once_cell的例子相比,我們用OnceLock代替了OnceCell,但其余的代碼仍然是相同的。OnceLock類型還公開了一個名為get_or_init的方法,該方法提供了與OnceCell的get_or_init相同的功能。

與lazy_static相比,我們可以使用LazyLock類型在聲明級別指定初始化函數(shù),而不必使用宏:

use std::sync::LazyLock;

static LOG_LEVEL: LazyLock<String> = LazyLock::new(get_log_level);

fn get_log_level() -> String {
    match std::env::var("LOG_LEVEL") {
        Ok(s) => s,
        Err(_) => "WARN".to_string(),
    }
}

fn main() {
    println!("{}", *LOG_LEVEL);
}

這里我們傳遞一個初始化函數(shù)給LazyLock的new方法,當(dāng)變量的值第一次被訪問時,類型內(nèi)部調(diào)用這個函數(shù)來初始化這個值。

標(biāo)準(zhǔn)庫與lazy_static和once_cell之間的比較

與lazy_static和once_cell這兩種crate相比,標(biāo)準(zhǔn)庫提供的延遲初始化類型的一大優(yōu)點是不需要任何額外的依賴項。盡管這兩個crate本身只有幾個依賴項,但這仍然意味著你的項目將有更多的依賴項,并且需要更多的編譯時間。

標(biāo)準(zhǔn)庫提供的延遲初始化類型的另一個優(yōu)點是它們是由官方rust標(biāo)準(zhǔn)庫團隊直接開發(fā)和維護的。

總結(jié)

將lazy_static初始化類型引入Rust標(biāo)準(zhǔn)庫本身,為在代碼中使用延遲初始化提供了很多便利,而無需添加另一個crate作為依賴項。

有了這些類型,我們就可以只在需要的時候進行昂貴的計算,并且只初始化一次昂貴的結(jié)構(gòu),比如正則表達(dá)式,而不必每次都手工進行初始化檢查。

相信隨著時間的推移,我們會看到更多項目使用標(biāo)準(zhǔn)庫中的延遲初始化類型,而不是在新創(chuàng)建的項目中引入外部crate。

責(zé)任編輯:武曉燕 來源: coding到燈火闌珊
相關(guān)推薦

2016-11-11 00:33:25

雙重檢查鎖定延遲初始化線程

2022-07-27 08:56:29

Go程序多版本

2023-11-12 23:08:17

C++初始化

2010-03-25 14:42:33

2009-09-02 16:52:55

C#數(shù)組初始化

2010-03-11 19:25:35

Python環(huán)境

2009-09-07 09:24:26

2025-02-13 11:11:53

Redis哨兵代碼

2011-06-17 15:29:44

C#對象初始化器集合初始化器

2021-03-12 10:30:11

SpringMVC流程初始化

2010-07-28 10:22:33

FlexApplica

2022-07-06 10:37:45

SpringServlet初始化

2020-12-03 09:50:52

容器IoC流程

2019-11-04 13:50:36

Java數(shù)組編程語言

2009-09-08 09:48:34

LINQ初始化數(shù)組

2009-11-11 15:29:15

ADO初始化

2024-01-15 06:34:09

Gin鏡像容器

2010-02-05 17:16:05

C++構(gòu)造函數(shù)

2009-02-13 10:33:00

交換機初始化配置

2009-06-11 13:26:16

Java數(shù)組聲明創(chuàng)建
點贊
收藏

51CTO技術(shù)棧公眾號