我尝试使用线程本地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
块吗?
答案 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的新手。