下面的两个rust函数除了一个返回一个不可变的引用,另一个返回一个可变的引用外,其他都是相同的。由于这两个函数都不涉及多次借用,所以我看不出这两个函数的工作原理有什么不同。然而,具有可变引用的函数会导致编译错误,而具有不可变引用的函数则不会:
// This complies with no problems
fn foo<'a>() {
let _: &'a () = &();
}
// This does not compile (see error below)
fn foo_mut<'a>() {
let _: &'a mut () = &mut ();
}
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:14:30
|
13 | fn foo_mut<'a>() {
| -- lifetime `'a` defined here
14 | let _: &'a mut () = &mut ();
| ---------- ^^ creates a temporary which is freed while still in use
| |
| type annotation requires that borrow lasts for `'a`
15 | }
| - temporary value is freed at the end of this statement
For more information about this error, try `rustc --explain E0716`.
error: could not compile `playground` due to previous error
当没有显式生存期时,代码也没有编译问题,这也可能是相关的:
// This also compiles with no problem
fn foo_mut_without_lifetime() {
let _: &mut () = &mut ();
}
看起来唯一的问题是试图存储一个具有生存期的可变引用,而不可变引用和没有显式生存期的引用都没有问题。为什么会发生这种情况,我该如何解决它?
1条答案
按热度按时间jpfvwuh41#
注意,这里的
()
或泛型生存期没有什么特别之处。而这并不:
那么为什么允许不可变引用呢?
当你引用一个值的时候,Rust会根据这个值将要死的地方来推断它的生命周期,下面是一个例子:
由于
x
在块的末尾死亡,Rust知道y
引用的生存期应该也只延长到块的末尾,因此,在x
死亡之后,它会阻止你使用它。这看起来很明显。但是请花点时间思考一下。在下面的代码中:
x
的推断生存期是多少?你可能会忍不住说“和块A一样”。但这实际上是不正确的。为什么?因为Rust比这聪明一点。它知道3
是一个 * 常量 *,因此Rust可以将3
放入最终可执行文件的常量表中。而且由于常量表的持续时间与最终程序的生命周期一样长,**Rust可以推断表达式&3
的生命周期为'static
。然后一切都很好,因为&'static
可以根据需要强制转换为任何其他生命周期!Rust在常量和临时变量之间划出了一条明确的界限,使用常量表达式的好处之一是对任何常量进行不可变的引用都会产生一个
'static
生存期。**临时变量则不是这样,下面的代码将无法编译:这是因为对于临时变量,Rust不能把它们放在可执行文件的常量表中,因为它们必须按需计算,因此与它们所在的作用域共享相同的生命周期。
好的,这很好,但是为什么不允许常量的 mutable 引用为
'static
呢?允许这样做有两个问题:
1.在一些架构上,常量表是不能修改的。WASM和一些嵌入式架构,以及所有哈佛架构的机器都是如此。提供
&mut
引用完全是无稽之谈,因为它们是不可变的。而且这种基本的借位检查规则在不同的平台之间应该没有区别。&'static mut
引用是危险的,因为它实际上是一个全局变量。