Rustのグローバル変数(可変)について調べた話。正直自信がない。
use once_cell::sync::Lazy; // 1.3.1 use std::sync::Mutex;
struct Foo { a: i32, b: i32, } impl Foo{ fn new() -> Foo { Foo { a: 1, b: 1, } } }
// グローバル変数 static myGlobal: Lazy<Mutex<Foo>> = Lazy::new(|| Mutex::new( Foo::new() ) );
fn call_1(){ let mut myg: std::sync::MutexGuard<'_, Foo> = myGlobal.lock().unwrap(); myg.a += 1; }
fn call_2(){ let mut myg: std::sync::MutexGuard<'_, Foo> = myGlobal.lock().unwrap(); myg.a += 1; }
fn main() { call_1(); call_2(); // myGlobal のミューテックスガードを取得 let mut myg: std::sync::MutexGuard<'_, Foo> = myGlobal.lock().unwrap(); myg.a += 1; println!("myg.a= {} , myg.b= {} ", myg.a,myg.b ); }
[package]
name = "rs-static"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
once_cell = "1.3.1"
グローバル変数はstaticをつけなければならない。
しかし、staticで定義できるのは定数のみ。従ってstaticだけではかなり限定的な使い方しかできない。
Mutexをつけると、
1.スレッドセーフになるのでunsafeをつけなくてもよくなる
2.内部可変性パターンにより、変数をmutableにできる
これにより、staticをつけながら可変な変数を定義できる。
つまり、可変なグローバル変数はMutexが必要。
Lazyは変数を遅延初期化するための機能。遅延初期化は、変数へ最初にアクセスしたときに初期化が発生するようにする。
初期化のタイミングをコントロールするためには、Lazyが必要。
正直、なくても動かすことはできる。
少なくとも、今回の小規模なプログラムに関しては。
ただ、初期化のタイミングがコンパイル時になる。さらにMutex::new()に与える引数が定数でなければならなくなるため、わざわざconst fnをimplしないといけなくなる。
lazyの || は無名関数を定義するためのもので、以下のように使用する。引数、戻り値型は省略可。処理を括る{}も省略できる。
fn main() { // let func = | 引数 | -> 戻り値型{処理}; let func = | x:i32 , y:i32 | -> f32 { ( x + y ) as f32 }; let a = func(1,2); println!("a = {} ", a ); }
// use once_cell::sync::Lazy; //Lazyは必須ではない use std::sync::Mutex; struct Foo { a: i32, b: i32, } impl Foo{ fn new() -> Foo { Foo { a: 1, b: 1, } } const fn new_const() -> Foo {// constをつけて定数のFooを返せる Foo { a: 1, b: 1, } } } // グローバル変数 // Lazyがないときは new_constにしなければいけない static myGlobal: Mutex<Foo> = Mutex::new( Foo::new_const() ); // 以下同じ
use once_cell::sync::Lazy; use std::sync::Mutex; // グローバル変数 static myGlobal: Lazy<Mutex<Vec<i32> > >= Lazy::new(|| Mutex::new( vec![] )); fn call_1(){ let mut myg:std::sync::MutexGuard<'_, Vec<i32>> = myGlobal.lock().unwrap(); myg.push(1); }
use once_cell::sync::Lazy; use std::sync::Mutex;
#[derive(Debug)] struct Foo { a: i32, b: i32, } impl Foo{ fn new() -> Foo { Foo { a: 1, b: 1, } } }
// グローバル変数 static myGlobal: Lazy<Mutex<Box<Foo> > >= Lazy::new(|| Mutex::new( Box::new(Foo::new()) ));
fn call_1(){ let mut myg:std::sync::MutexGuard<'_, Box<Foo>> = myGlobal.lock().unwrap(); myg.a += 1; }