为什么我不能对一个永远不会超出范围的值进行静态引用?
Why can't I make a static reference to a value that never goes out of scope?
为什么我不能 'static
引用一个永远不会超出范围的值?
如果它永远不会超出范围,比如当函数调用永远不会在主线程中 returns 时,那么只要范围拥有数据,数据就会保持有效,这将是程序。在那种情况下,我也应该能够在程序的整个生命周期内引用它,因为它在这段时间内保持有效,对吗?这是我的问题的示例:
fn noreturn() -> ! {
loop {}
}
fn main() {
// This value is never dropped or moved, and so it should last
// for 'static, right?
let not_dropped = 0usize;
// So I should be able to borrow it for 'static here, right?
let permanent_ref: &'static usize = ¬_dropped;
// This never returns, and so the value is never dropped
// and the data stays valid,
noreturn()
// .. but the compiler complains that not_dropped is dropped
// here even though it's never dropped. Why?
}
如果保证永远不会到达具有此值的范围的末尾,那么我应该能够永远持有对该范围所拥有的有效值的引用,对吗?我在概念上是否遗漏了什么?
不返回不等同于不退出。例如,用 panic
替换循环(签名保持不变)。然后添加一个值,当它被删除时打印出来:
fn noreturn() -> ! {
panic!()
}
fn main() {
let not_dropped = Noisy;
noreturn()
}
struct Noisy;
impl Drop for Noisy {
fn drop(&mut self) {
eprintln!("I was dropped");
}
}
您会看到该值确实下降了。
另一种看待这个问题的方法是,如果您在子线程 1 中执行此操作,子线程 1 生成了子线程 2。线程 2 引用了 &'static
值,然后线程 1 退出并且堆栈是走了。当线程 2 试图访问引用的值时,它是内存不安全。
What if the noreturn
function guaranteed no exit by just containing a loop, like in the example I showed? Is that a case where this should be possible?
Rust 中没有表面语法来保证函数 运行 永远存在,因此编译器无法为您保证这一点。但是,如果您知道编译器不知道的内容,您可以使用 unsafe
来表达。
例如,也许您知道您的函数调用 process::abort
(或者 panic
通过编译器选项实现为中止),因此任何代码都不可能 运行函数退出。在那种情况下,我相信(但尚未验证)您可以使用 unsafe 将生命周期更改为 'static
.
也就是说,调用 Box::leak
是获取 &'static
值的一种更简单的方法。
当一开始在 Rust 中有些东西不太有意义时,答案几乎总是 “你在多线程场景中考虑过这个吗?”
not_dropped
存在于主线程的堆栈帧中,如果主线程崩溃或退出,那么您从主线程的堆栈帧传递给另一个线程的任何“静态”引用都将变得无效:
use std::thread;
fn no_return() -> ! {
loop {}
}
fn main() {
let not_dropped = 0; // note: can actually be dropped
let permanent_ref: &'static i32 = ¬_dropped; // note: not actually permanent
// pass permanent_ref to 2nd thread
thread::spawn(move || {
// imagine this thread also does some infinite loop
loop {
println!("{}", permanent_ref);
}
});
// now imagine this infinite loops crashes / panics
no_return();
// main thread exits, not_dropped is dropped
// permanent_ref is now invalidated in 2nd thread
}
为什么我不能 'static
引用一个永远不会超出范围的值?
如果它永远不会超出范围,比如当函数调用永远不会在主线程中 returns 时,那么只要范围拥有数据,数据就会保持有效,这将是程序。在那种情况下,我也应该能够在程序的整个生命周期内引用它,因为它在这段时间内保持有效,对吗?这是我的问题的示例:
fn noreturn() -> ! {
loop {}
}
fn main() {
// This value is never dropped or moved, and so it should last
// for 'static, right?
let not_dropped = 0usize;
// So I should be able to borrow it for 'static here, right?
let permanent_ref: &'static usize = ¬_dropped;
// This never returns, and so the value is never dropped
// and the data stays valid,
noreturn()
// .. but the compiler complains that not_dropped is dropped
// here even though it's never dropped. Why?
}
如果保证永远不会到达具有此值的范围的末尾,那么我应该能够永远持有对该范围所拥有的有效值的引用,对吗?我在概念上是否遗漏了什么?
不返回不等同于不退出。例如,用 panic
替换循环(签名保持不变)。然后添加一个值,当它被删除时打印出来:
fn noreturn() -> ! {
panic!()
}
fn main() {
let not_dropped = Noisy;
noreturn()
}
struct Noisy;
impl Drop for Noisy {
fn drop(&mut self) {
eprintln!("I was dropped");
}
}
您会看到该值确实下降了。
另一种看待这个问题的方法是,如果您在子线程 1 中执行此操作,子线程 1 生成了子线程 2。线程 2 引用了 &'static
值,然后线程 1 退出并且堆栈是走了。当线程 2 试图访问引用的值时,它是内存不安全。
What if the
noreturn
function guaranteed no exit by just containing a loop, like in the example I showed? Is that a case where this should be possible?
Rust 中没有表面语法来保证函数 运行 永远存在,因此编译器无法为您保证这一点。但是,如果您知道编译器不知道的内容,您可以使用 unsafe
来表达。
例如,也许您知道您的函数调用 process::abort
(或者 panic
通过编译器选项实现为中止),因此任何代码都不可能 运行函数退出。在那种情况下,我相信(但尚未验证)您可以使用 unsafe 将生命周期更改为 'static
.
也就是说,调用 Box::leak
是获取 &'static
值的一种更简单的方法。
当一开始在 Rust 中有些东西不太有意义时,答案几乎总是 “你在多线程场景中考虑过这个吗?”
not_dropped
存在于主线程的堆栈帧中,如果主线程崩溃或退出,那么您从主线程的堆栈帧传递给另一个线程的任何“静态”引用都将变得无效:
use std::thread;
fn no_return() -> ! {
loop {}
}
fn main() {
let not_dropped = 0; // note: can actually be dropped
let permanent_ref: &'static i32 = ¬_dropped; // note: not actually permanent
// pass permanent_ref to 2nd thread
thread::spawn(move || {
// imagine this thread also does some infinite loop
loop {
println!("{}", permanent_ref);
}
});
// now imagine this infinite loops crashes / panics
no_return();
// main thread exits, not_dropped is dropped
// permanent_ref is now invalidated in 2nd thread
}