サーチ…


構文

  • const IDENTIFIER:タイプ= constexpr;
  • static [mut] IDENTIFIER:タイプ= expr;
  • lazy_static! {静的参照IDENTIFIER:タイプ= expr; }

備考

  • const値は常にインラインであり、メモリ内にアドレスはありません。
  • static値はインライン化されず、固定アドレスを持つ1つのインスタンスを持ちます。
  • static mut値はメモリセーフではないため、 unsafeブロックでしかアクセスできません。
  • マルチスレッドコードでグローバル静的可変変数を使用すると危険な場合がありますので、 std :: sync :: Mutexやその他の方法を使用することを検討してください
  • lazy_staticオブジェクトは不変であり、一度だけ初期化され、すべてのスレッド間で共有され、直接アクセスすることができます(ラッパータイプは関係ありません)。対照的に、 thread_localオブジェクトは可変であり、スレッドごとに1回初期化され、アクセスは間接的です(ラッパータイプLocalKey<T>

Const

constキーワードは、グローバル定数バインディングを宣言します。

const DEADBEEF: u64 = 0xDEADBEEF;

fn main() {
    println("{:X}", DEADBEEF);
}

この出力

DEADBEEF

静的

staticキーワードはグローバル静的バインディングを宣言します。

static HELLO_WORLD: &'static str = "Hello, world!";

fn main() {
    println("{}", HELLO_WORLD);
}

この出力

Hello, world!

lazy_static!

実行時に初期化されるグローバル不変変数を作成するには、 lazy_staticクレートを使用します。 HashMapをデモンストレーションとして使用します。

Cargo.toml

[dependencies]
lazy_static = "0.1.*"

main.rs

#[macro_use]
extern crate lazy_static;

lazy_static! {
    static ref HASHMAP: HashMap<u32, &'static str> = {
        let mut m = HashMap::new();
        m.insert(0, "hello");
        m.insert(1, ",");
        m.insert(2, " ");
        m.insert(3, "world");
        m
    };
    static ref COUNT: usize = HASHMAP.len();
}

fn main() {
    // We dereference COUNT because it's type is &usize
    println!("The map has {} entries.", *COUNT);

    // Here we don't dereference with * because of Deref coercions
    println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap());
}

スレッドローカルオブジェクト

スレッドローカルオブジェクトは、スレッドで最初に使用されるときに初期化されます。名前が示すように、各スレッドは他のスレッドから独立した新しいコピーを取得します。

use std::cell::RefCell;
use std::thread;

thread_local! {
    static FOO: RefCell<f32> = RefCell::new(1.0);
}

// When this macro expands, `FOO` gets type `thread::LocalKey<RefCell<f32>>`.
//
// Side note: One of its private member is a pointer to a function which is
// responsible for returning the thread-local object. Having all its members
// `Sync` [0], `LocalKey` is also implicitly `Sync`.
//
// [0]: As of writing this, `LocalKey` just has 2 function-pointers as members

fn main() {
    FOO.with(|foo| {
        // `foo` is of type `&RefCell<f64>`
        *foo.borrow_mut() = 3.0;
    });

    thread::spawn(move|| {
        // Note that static objects do not move (`FOO` is the same everywhere),
        // but the `foo` you get inside the closure will of course be different.
        FOO.with(|foo| {
            println!("inner: {}", *foo.borrow());
        });
    }).join().unwrap();

    FOO.with(|foo| {
        println!("main: {}", *foo.borrow());
    });
}

出力:

inner: 1
main: 3

mut_staticで安全な静的mut

コンパイラがそれらが適切に使用されていることを保証することは困難であるため、変更可能なグローバル項目( static mutと呼ばれ、使用に伴う固有の矛盾を強調する)は安全ではありません。

しかし、データの周りに相互排他的なロックを導入することにより、メモリセーフな可変グローバルを実現します。これは論理的には安全だとは限りません。

#[macro_use]
extern crate lazy_static;
extern crate mut_static;

use mut_static::MutStatic;

pub struct MyStruct { value: usize }

impl MyStruct {
    pub fn new(v: usize) -> Self{
        MyStruct { value: v }
    }
    pub fn getvalue(&self) -> usize { self.value }
    pub fn setvalue(&mut self, v: usize) { self.value = v }
}

lazy_static! {
    static ref MY_GLOBAL_STATE: MutStatic<MyStruct> = MutStatic::new();
}

fn main() {
    // Here, I call .set on the MutStatic to put data inside it.
    // This can fail.
    MY_GLOBAL_STATE.set(MyStruct::new(0)).unwrap();
    {
        // Using the global state immutably is easy...
        println!("Before mut: {}", 
                 MY_GLOBAL_STATE.read().unwrap().getvalue());
    }
    {
         // Using it mutably is too...
         let mut mut_handle = MY_GLOBAL_STATE.write().unwrap();
         mut_handle.setvalue(3);
         println!("Changed value to 3.");
    } 
    {
        // As long as there's a scope change we can get the 
        // immutable version again...
        println!("After mut: {}", 
                 MY_GLOBAL_STATE.read().unwrap().getvalue());
    }
    {
        // But beware! Anything can change global state!
        foo();
        println!("After foo: {}", 
                 MY_GLOBAL_STATE.read().unwrap().getvalue());
    }
 
}

// Note that foo takes no parameters
fn foo() {
    let val;
    {
        val = MY_GLOBAL_STATE.read().unwrap().getvalue();
    }
    {
        let mut mut_handle = 
            MY_GLOBAL_STATE.write().unwrap();
        mut_handle.setvalue(val + 1);
    }
}

このコードは次の出力を生成します。

Before mut: 0
Changed value to 3.
After mut: 3
After foo: 4

これは通常はRustで起こるはずのものではありません。 foo()は何にも変更可能な参照を取らなかったので、何かを変更してはいけません。これにより、ロジックエラーをデバッグするのが非常に困難になります。

一方、時にはこれはまさにあなたが望むものです。たとえば、多くのゲームエンジンでは、画像やその他のリソースをグローバルにキャッシュする必要があります。これは遅延ロード(または他の複雑なローディング戦略を使用します)です.MutStaticはその目的に最適です。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow