lazy_static은 이미 유행이 지났다!?once_벨을 사용하세요.

14354 단어 Rusttech

이 문장을 세 줄로 요약하면

  • Rust의 글로벌 변수에는 많은 제한이 있음
  • 제한을 없애고 전역 변수를 사용하기 쉬운 크레인lazy_static
  • lazy_static의 대체품once_cell으로 등장
  • Rust의 글로벌 변수에는 많은 제한이 있습니다.


    Rust에 글로벌 변수가 있음
  • 상수로만 초기화
  • 변경할 수 있는 경우 unsafe
  • 필요
  • 변경할 수 없으면 라인 안전형
  • 만 사용 가능
    이런 제한이 있어서 사용하기 매우 어려운 물건이다.
    예를 들어 커다란 텍스트를 한 번만 읽고 전역 변수에 저장하려고 합니다.
    그러나 이렇게 쓰면unsafe 없으면 전역 변수를 변경할 수 없어 컴파일 오류가 발생합니다.
    static mut LARGE_TEXT : String = String::new();
    fn main() {
      LARGE_TEXT = load_large_text();
    }
    
    /// 巨大なテキストを読み込む
    fn load_large_text() -> String {
      todo!()
    }
    
    error[E0133]: use of mutable static is unsafe and requires unsafe function or block
     --> src\main.rs:3:3
      |
    3 |   LARGE_TEXT = load_large_text();
      |   ^^^^^^^^^^ use of mutable static
      |
      = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
    
    unsafe를 사용하면 컴파일 오류가 사라지지만 커다란 텍스트를 사용할 때 실수로 다시 쓸 수 있어 위험합니다.
    static mut LARGE_TEXT: String = String::new();
    fn main() {
        unsafe {
            // 今LARGE_TEXTを使用していないとは限らない、その事をどうか思い出して頂きたい
            LARGE_TEXT = load_large_text();
        }
    }
    
    RefCell를 사용하면 실행 시 사용 여부를 확인하고 안전하다고 판단되면 RefCell 라인이 안전하지 않아 사용할 수 없습니다.
    use std::cell::RefCell;
    static LARGE_TEXT: RefCell<String> = RefCell::new(String::new());
    fn main() {
        *LARGE_TEXT.borrow_mut() = load_large_text();
    }
    
    error[E0277]: `std::cell::RefCell<std::string::String>` cannot be shared between threads safely
     --> src\main.rs:2:1
      |
    2 | static LARGE_TEXT: RefCell<String> = RefCell::new(String::new());
      | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::RefCell<std::string::String>` cannot be shared between threads safely
      |
      = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell<std::string::String>`
      = note: shared static variables must have a type that implements `Sync`
    
    그렇다면RefCell의 라인 안전판Mutex이라면 전역 변수가 상수 이외에서 초기화되지 않아 사용할 수 없습니다.
    use std::sync::Mutex;
    static LARGE_TEXT: Mutex<String> = Mutex::new(String::new());
    fn main() {
        *LARGE_TEXT.lock().unwrap() = load_large_text();
    }
    
    error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
     --> src\main.rs:2:36
      |
    2 | static LARGE_TEXT: Mutex<String> = Mutex::new(String::new());
      |
    
    "Rust의 전역 변수는 사용할 수 없습니다!"
    그렇게 생각하는 네가 정답이다.
    전역 변수를 직접 사용하지 말고 더 쉽게 사용할 수 있는 크레인을 사용하세요.

    제한을 없애면 전역 변수의 크레인을 사용하기 쉽다static

    lazy_static를 사용하면 첫 방문할 때 초기화 처리를 한 번만 수행하는 전역 변수를 만들 수 있습니다.
    use lazy_static::lazy_static;
    lazy_static! {
        static ref LARGE_TEXT: String = load_large_text();
    }
    fn main() {
        println!("{}", *LARGE_TEXT);
    }
    
    lazy_static는 매우 편리하여 곧 공장 표준의 지위에 올랐다.
    그런데 이거lazy_static는 매크로를 사용했기 때문에 이해하기 어렵지 않나요?

    lazy_static의 대체 once셀이 등장합니다.


    이 가운데 lazy_static와 같은 처리를 구현한 매크로 없음once_cell이 등장했다.
    방금lazy_static의 예로once_cell를 사용하면 다음과 같다.
    use once_cell::sync::Lazy;
    static LARGE_TEXT: Lazy<String> = Lazy::new(|| load_large_text());
    fn main() {
        println!("{}", *LARGE_TEXT);
    }
    
    매크로를 사용하지 않았기 때문에 이 변수를 함수나 구조 구성원에게 전달할 수도 있습니다.
    fn may_use_large_text(large_text: &Lazy<String>) {
      todo!()
    }
    
    struct LargeTextCache {
        large_text: Lazy<String>,
    }
    
    다운로드 수는 아직 lazy_static에 미치지 못했지만 급속히 증가하고 있다표준 라이브러리 가입도 고려.

    Links


    lazy_static
    https://github.com/rust-lang-nursery/lazy-static.rs
    once_cell
    https://github.com/matklad/once_cell

    좋은 웹페이지 즐겨찾기