Rust 为什么可以';我对一个永远不会超出范围的值进行静态引用吗?

Rust 为什么可以';我对一个永远不会超出范围的值进行静态引用吗?,rust,reference,lifetime,borrow-checker,borrowing,Rust,Reference,Lifetime,Borrow Checker,Borrowing,为什么我不能对一个永远不会超出范围的值进行静态引用 如果它从未超出作用域,比如函数调用从未在主线程中返回,那么只要作用域拥有数据,数据就会保持有效,这将持续到程序的生命周期。在这种情况下,我应该能够在程序生命周期内引用它,因为它在该生命周期内保持有效,对吗?以下是我的问题的一个例子: fn noreturn()->!{ 循环{} } fn main(){ //此值永远不会被删除或移动,因此它应该持续 //对于“静态”,对吗? 不要放弃=0使用; //所以我应该可以借它来做“静电”,对吗? 让永久

为什么我不能对一个永远不会超出范围的值进行
静态
引用

如果它从未超出作用域,比如函数调用从未在主线程中返回,那么只要作用域拥有数据,数据就会保持有效,这将持续到程序的生命周期。在这种情况下,我应该能够在程序生命周期内引用它,因为它在该生命周期内保持有效,对吗?以下是我的问题的一个例子:

fn noreturn()->!{
循环{}
}
fn main(){
//此值永远不会被删除或移动,因此它应该持续
//对于“静态”,对吗?
不要放弃=0使用;
//所以我应该可以借它来做“静电”,对吗?
让永久引用:&'static usize=¬\u删除;
//这永远不会返回,因此该值永远不会被删除
//数据保持有效,
诺雷图恩()
//..但编译器抱怨未删除的内容被删除
//在这里,即使它从未掉下。为什么?
}
如果保证永远不会到达具有此值的作用域的末尾,那么我应该能够永远保存对该作用域所拥有的有效值的引用,对吗?从概念上讲,我在这里遗漏了什么吗?

不返回并不等于不退出。例如,将循环替换为一个
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中执行此操作,则会产生子线程2。线程2引用了
&'static
值,然后线程1退出,堆栈消失。当线程2尝试访问引用的值时,内存不安全

如果
noreturn
函数通过只包含一个循环来保证不退出,如我展示的示例中所示,该怎么办?在这种情况下,这应该是可能的吗

Rust中没有表面语法来保证函数永远运行,因此编译器无法为您保证这一点。但是,如果您知道编译器不知道的东西,可以使用
safe
来表示

例如,您可能知道您的函数调用了
process::abort
(或者
panic
是通过编译器选项实现为abort的),因此函数退出后不可能运行任何代码。在这种情况下,我相信(但尚未验证)您可以使用“不安全”将生存期更改为“静态”


也就是说,调用是获取
&'static
值的一种简单得多的方法。

当在Rust中一开始有些东西不太合理时,答案几乎总是“您在多线程场景中考虑过这一点吗?”

not_drop
存在于主线程的堆栈帧中,如果主线程崩溃或退出,则从主线程的堆栈帧传递到另一个线程的任何“静态”引用都将无效:

使用std::thread;
fn不返回()->!{
循环{}
}
fn main(){
let not_drop=0;//注意:实际上可以删除
让permanent_ref:&'static i32=¬_drop;//注意:实际上不是永久的
//将永久_参考传递到第二个螺纹
线程::生成(移动| |{
//想象一下,这个线程也执行一些无限循环
环路{
println!(“{}”,永久参考);
}
});
//现在想象一下这个无限循环崩溃/恐慌
无返回();
//主线程退出,未删除的线程被删除
//永久参考现在在第二个线程中无效
}

如果主线程死机或退出,则整个程序终止。但是,仍然可以(如果不可取的话)从非主线程手动调用
main
,因此参数仍然有效。基本上,
main
是特殊的,但并没有那么特殊。而Rust
main
不是操作系统
main
。可能是主线程退出,然后操作系统安排子线程在主线程退出之前运行。不安全的另一个例子。“你会看到该值确实被删除了。”只有在恐慌未设置为中止时才如此。@Acorn确实如此。我将扩展现有的关于中止的文本以涵盖这一点。@masklin这是我回答的要点;你能建议一个我可以改进措辞的方法吗<代码>->并不意味着“永不退出”,它意味着“永不返回”。例如,
panic
是一个发散函数(如答案所示),它会导致线程退出,但不会返回控制。我甚至指出,在线程展开过程中,堆栈变量会被丢弃,如果将其视为
'静态
,则会导致内存不安全。啊,是的,你当然是对的。反对撤回。