Return 对惰性静态 RwLock 中的 T 的引用<Option<T>>?
Return a reference to a T inside a lazy static RwLock<Option<T>>?
我有一个惰性静态结构,我希望能够在程序执行开始时将其设置为某个随机值,然后再获取。这个愚蠢的小片段可以用作示例:
use lazy_static::lazy_static;
use std::sync::RwLock;
struct Answer(i8);
lazy_static! {
static ref ANSWER: RwLock<Option<Answer>> = RwLock::new(None);
}
fn answer_question() {
*ANSWER.write().unwrap() = Some(Answer(42));
}
fn what_is_the_answer() -> &'static Answer {
ANSWER
.read()
.unwrap()
.as_ref()
.unwrap()
}
此代码无法编译:
error[E0515]: cannot return value referencing temporary value
--> src/lib.rs:15:5
|
15 | ANSWER
| _____^
| |_____|
| ||
16 | || .read()
17 | || .unwrap()
| ||_________________- temporary value created here
18 | | .as_ref()
19 | | .unwrap()
| |__________________^ returns a value referencing data owned by the current function
我知道您不能 return 对临时值的引用。但是我想要 return 对 ANSWER
的引用,它是静态的——与临时的完全相反!我猜这是第一个调用 unwrap
return 的 RwLockReadGuard
问题?
我可以通过更改 return 类型来获取要编译的代码:
fn what_is_the_answer() -> RwLockReadGuard<'static, Option<Answer>> {
ANSWER
.read()
.unwrap()
}
但是现在调用代码变得非常不符合人体工程学 - 我必须进行两次额外的调用才能获得实际值:
what_is_the_answer().as_ref().unwrap()
我能否以某种方式return从该函数引用静态ANSWER
?我可以通过某种方式映射到 return a RwLockReadGuard<&Answer>
吗?
据我了解您的意图,Answer
的值无法在 lazy_static
中初始化时计算,而是取决于仅在 answer_question
时才知道的参数叫做。以下可能不是最优雅的解决方案,但它允许 &'static
引用一个值,该值依赖于仅在运行时已知的参数。
基本方法是使用两个 lazy_static
值,其中一个用作执行必要同步的“代理”,另一个是值本身。这避免了在访问 ANSWER
.
时必须访问多层锁和解包 Option
-values
ANSWER
值通过等待 CondVar
来初始化,当值计算完成时它会发出信号。然后将该值放置在 lazy_static
中,并且从那时起不可移动。因此 &'static
是可能的(参见 get_the_answer()
)。我选择 String
作为 example-type。请注意,在不调用 generate_the_answer()
的情况下访问 ANSWER
将导致初始化永远等待,从而使程序死锁。
use std::{sync, thread};
lazy_static::lazy_static! {
// A proxy to synchronize when the value is generated
static ref ANSWER_PROXY: (sync::Mutex<Option<String>>, sync::Condvar) = {
(sync::Mutex::new(None), sync::Condvar::new())
};
// The actual value, which is initialized from the proxy and stays in place
// forever, hence allowing &'static access
static ref ANSWER: String = {
let (lock, cvar) = &*ANSWER_PROXY;
let mut answer = lock.lock().unwrap();
loop {
// As long as the proxy is None, the answer has not been generated
match answer.take() {
None => answer = cvar.wait(answer).unwrap(),
Some(answer) => return answer,
}
}
};
}
// Generate the answer and place it in the proxy. The `param` is just here
// to demonstrate we can move owned values into the proxy
fn generate_the_answer(param: String) {
// We don't need a thread here, yet we can
thread::spawn(move || {
println!("Generating the answer...");
let mut s = String::from("Hello, ");
s.push_str(¶m);
thread::sleep(std::time::Duration::from_secs(1));
let (lock, cvar) = &*ANSWER_PROXY;
*lock.lock().unwrap() = Some(s);
cvar.notify_one();
println!("Answer generated.");
});
}
// Nothing to see here, except that we have a &'static reference to the answer
fn get_the_answer() -> &'static str {
println!("Asking for the answer...");
&ANSWER
}
fn main() {
println!("Hello, world!");
// Accessing `ANSWER` without generating it will deadlock!
//get_the_answer();
generate_the_answer(String::from("John!"));
println!("The answer is \"{}\"", get_the_answer());
// The second time a value is generated, noone is listening.
// This is the flipside of `ANSWER` being a &'static
generate_the_answer(String::from("Peter!"));
println!("The answer is still \"{}\"", get_the_answer());
}
once_cell
是为此设计的:在 answer_question
中使用 .set(...).unwrap()
并在 what_is_the_answer
中使用 .get().unwrap()
。
我有一个惰性静态结构,我希望能够在程序执行开始时将其设置为某个随机值,然后再获取。这个愚蠢的小片段可以用作示例:
use lazy_static::lazy_static;
use std::sync::RwLock;
struct Answer(i8);
lazy_static! {
static ref ANSWER: RwLock<Option<Answer>> = RwLock::new(None);
}
fn answer_question() {
*ANSWER.write().unwrap() = Some(Answer(42));
}
fn what_is_the_answer() -> &'static Answer {
ANSWER
.read()
.unwrap()
.as_ref()
.unwrap()
}
此代码无法编译:
error[E0515]: cannot return value referencing temporary value
--> src/lib.rs:15:5
|
15 | ANSWER
| _____^
| |_____|
| ||
16 | || .read()
17 | || .unwrap()
| ||_________________- temporary value created here
18 | | .as_ref()
19 | | .unwrap()
| |__________________^ returns a value referencing data owned by the current function
我知道您不能 return 对临时值的引用。但是我想要 return 对 ANSWER
的引用,它是静态的——与临时的完全相反!我猜这是第一个调用 unwrap
return 的 RwLockReadGuard
问题?
我可以通过更改 return 类型来获取要编译的代码:
fn what_is_the_answer() -> RwLockReadGuard<'static, Option<Answer>> {
ANSWER
.read()
.unwrap()
}
但是现在调用代码变得非常不符合人体工程学 - 我必须进行两次额外的调用才能获得实际值:
what_is_the_answer().as_ref().unwrap()
我能否以某种方式return从该函数引用静态ANSWER
?我可以通过某种方式映射到 return a RwLockReadGuard<&Answer>
吗?
据我了解您的意图,Answer
的值无法在 lazy_static
中初始化时计算,而是取决于仅在 answer_question
时才知道的参数叫做。以下可能不是最优雅的解决方案,但它允许 &'static
引用一个值,该值依赖于仅在运行时已知的参数。
基本方法是使用两个 lazy_static
值,其中一个用作执行必要同步的“代理”,另一个是值本身。这避免了在访问 ANSWER
.
Option
-values
ANSWER
值通过等待 CondVar
来初始化,当值计算完成时它会发出信号。然后将该值放置在 lazy_static
中,并且从那时起不可移动。因此 &'static
是可能的(参见 get_the_answer()
)。我选择 String
作为 example-type。请注意,在不调用 generate_the_answer()
的情况下访问 ANSWER
将导致初始化永远等待,从而使程序死锁。
use std::{sync, thread};
lazy_static::lazy_static! {
// A proxy to synchronize when the value is generated
static ref ANSWER_PROXY: (sync::Mutex<Option<String>>, sync::Condvar) = {
(sync::Mutex::new(None), sync::Condvar::new())
};
// The actual value, which is initialized from the proxy and stays in place
// forever, hence allowing &'static access
static ref ANSWER: String = {
let (lock, cvar) = &*ANSWER_PROXY;
let mut answer = lock.lock().unwrap();
loop {
// As long as the proxy is None, the answer has not been generated
match answer.take() {
None => answer = cvar.wait(answer).unwrap(),
Some(answer) => return answer,
}
}
};
}
// Generate the answer and place it in the proxy. The `param` is just here
// to demonstrate we can move owned values into the proxy
fn generate_the_answer(param: String) {
// We don't need a thread here, yet we can
thread::spawn(move || {
println!("Generating the answer...");
let mut s = String::from("Hello, ");
s.push_str(¶m);
thread::sleep(std::time::Duration::from_secs(1));
let (lock, cvar) = &*ANSWER_PROXY;
*lock.lock().unwrap() = Some(s);
cvar.notify_one();
println!("Answer generated.");
});
}
// Nothing to see here, except that we have a &'static reference to the answer
fn get_the_answer() -> &'static str {
println!("Asking for the answer...");
&ANSWER
}
fn main() {
println!("Hello, world!");
// Accessing `ANSWER` without generating it will deadlock!
//get_the_answer();
generate_the_answer(String::from("John!"));
println!("The answer is \"{}\"", get_the_answer());
// The second time a value is generated, noone is listening.
// This is the flipside of `ANSWER` being a &'static
generate_the_answer(String::from("Peter!"));
println!("The answer is still \"{}\"", get_the_answer());
}
once_cell
是为此设计的:在 answer_question
中使用 .set(...).unwrap()
并在 what_is_the_answer
中使用 .get().unwrap()
。