如何访问线程局部LocalKey静态变量?

时间:2017-10-21 18:21:26

标签: rust

我尝试使用线程本地LocalKey来创建一个全局游戏变量,用户可以在游戏开始时设置一次。

我在PLAYER_NAME块中设置新的with时最终得到了编译:

use std::thread::LocalKey;
use std::borrow::BorrowMut;

thread_local! {
    pub static PLAYER_NAME: String = String::from("player-one");
}

fn main() {
    let p: String = String::from("new-name");

    PLAYER_NAME.with(|mut player_name| {
        let player_name = p;
    });

    println!("PLAYER_NAME is: {:?}", PLAYER_NAME);
}

打印出来:

PLAYER_NAME is: LocalKey { .. }

如何打印PLAYER_NAME的字符串值?每次我想阅读时都必须使用with块吗?

2 个答案:

答案 0 :(得分:3)

  

每次我想阅读时,是否必须使用with块?

如果您直接访问PLAYER_NAME,请单击是 - 请参阅@Shepmaster's answer以获取示例。但是,您通常在真实程序中执行的操作是封装对全局函数的访问,这些函数会向您购买您从其他语言中了解的使用模式,而不会降低性能或方便性。例如:

use std::cell::RefCell;

thread_local! {
    pub static PLAYER_NAME: RefCell<String>
        = RefCell::new("player-one".to_string());
}

fn set_player_name(name: String) {
    PLAYER_NAME.with(|player_name| {
        *player_name.borrow_mut() = name
    });
}

fn get_player_name() -> String {
    PLAYER_NAME.with(|player_name| player_name.borrow().clone())
}

fn main() {
    assert_eq!(get_player_name(), "player-one".to_string());
    set_player_name("mini me".to_string());
    assert_eq!(get_player_name(), "mini me".to_string());
}

如果您不希望播放器名称为每个线程,请将thread_local!替换为lazy_static!,将RefCell替换为RwLock,{{1 {}为borrow()read()borrow_mut(),您将不再需要write()

答案 1 :(得分:2)

  

如何打印PLAYER_NAME的字符串值?每次我想阅读时都必须使用with块吗?

是。编译器无法知道哪个对PLAYER_NAME的任意调用将是第一个调用,哪个调用将来自哪个。 每次时间访问本地线程,必须进行检查以确保它已初始化,如果没有,则执行此操作。 with执行该检查。

除此之外,您还有许多其他问题。 Rust是一种编译语言,这意味着你应该听取它打印的警告

let player_name = p;

这声明了一个新的变量,它隐藏了闭包变量player_name,它没有设置它。

然后您尝试改变不可变引用,这不起作用。您需要某种内部可变性,例如RefCell

use std::cell::RefCell;

thread_local! {
    pub static PLAYER_NAME: RefCell<String> = RefCell::new(String::from("player-one"));
}

fn main() {
    let p: String = String::from("new-name");

    PLAYER_NAME.with(|player_name| {
        *player_name.borrow_mut() = p;
    });

    PLAYER_NAME.with(|player_name| {
        println!("The name is: {}", player_name.borrow());
    });
}

另见:

我也强烈鼓励您尝试使用标准的Rust引用并从父上下文传递值。它通常比一些神奇的半全球状态更容易理解,特别是如果你是Rust的新手。