スポンサーリンク

Rustでグローバル変数を作る

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"

 

解説

1. staticをつける

グローバル変数はstaticをつけなければならない

しかし、staticで定義できるのは定数のみ。従ってstaticだけではかなり限定的な使い方しかできない。

2.Mutexを使う

Mutexをつけると、

1.スレッドセーフになるのでunsafeをつけなくてもよくなる

2.内部可変性パターンにより、変数をmutableにできる

これにより、staticをつけながら可変な変数を定義できる。

つまり、可変なグローバル変数はMutexが必要

3.Lazyを使う

Lazyは変数を遅延初期化するための機能。遅延初期化は、変数へ最初にアクセスしたときに初期化が発生するようにする。

初期化のタイミングをコントロールするためには、Lazyが必要

正直、なくても動かすことはできる。

少なくとも、今回の小規模なプログラムに関しては。

ただ、初期化のタイミングがコンパイル時になる。さらにMutex::new()に与える引数が定数でなければならなくなるため、わざわざconst fnをimplしないといけなくなる。

4.Lazyの || とは

lazyの || は無名関数を定義するためのもので、以下のように使用する。引数、戻り値型は省略可。処理を括る{}も省略できる。

fn main() {

  // let func = | 引数 | -> 戻り値型{処理};

  let func = 
        | x:i32 , y:i32 | -> f32 
        {
          ( x + y ) as f32 
        };

  let a = func(1,2);

  println!("a = {} ", a );

}

5.Lazyなし版

// 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()
      );

// 以下同じ

ほかの例

Vecの例

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);

}

Boxの例

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;

}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: