我正在读“生锈的lifetimes chapter”这本书,我偶然发现了这个例子,关于一个命名的/显式的生命周期:
struct Foo<'a> {
x: &'a i32,
}
fn main() {
let x; // -+ x goes into scope
// |
{ // |
let y = &5; // ---+ y goes into scope
let f = Foo { x: y }; // ---+ f goes into scope
x = &f.x; // | | error here
} // ---+ f and y go out of scope
// |
println!("{}", x); // |
} // -+ x goes out of scope
我很清楚,编译器防止的错误是在释放后使用分配给x
的引用:内部作用域完成后,f
和&f.x
都无效,不应该分配给x
。
我的问题是,在不使用显式'a
生存期的情况下,例如通过推断对更大范围(x = &f.x;
)的非法引用赋值,可以很容易地分析出问题。
在哪些情况下,确实需要显式的生命周期来防止在释放后使用(或其他类?)错误?
发布于 2015-07-24 21:38:00
其他的答案都有显著的要点(fjh's concrete example where an explicit lifetime is needed),但是缺少一个关键的东西:当编译器会告诉您错误的时候,为什么需要显式的生命周期
这实际上和“当编译器可以推断出显式类型时为什么需要显式类型”是同一个问题。一个假设的例子:
fn foo() -> _ {
""
}
当然,编译器可以看到我返回的是一个&'static str
,那么为什么程序员必须键入它呢?
主要原因是,虽然编译器可以看到您的代码做了什么,但它不知道您的意图是什么。
函数是防火墙的自然边界,不受代码更改的影响。如果我们允许从代码中完全检查生命周期,那么一个看起来无害的更改可能会影响生命周期,这可能会导致遥远的函数中出现错误。这不是一个假设的例子。据我所知,当你依赖顶级函数的类型推断时,Haskell就有这个问题。铁锈把那个特殊的问题扼杀在萌芽状态。
编译器还有一个效率优势--只需要解析函数签名就可以验证类型和生存期。更重要的是,它对程序员有效率上的好处。如果我们没有明确的生命周期,这个函数能做什么:
fn foo(a: &u8, b: &u8) -> &u8
不检查源代码就无法判断,这与大量的编码最佳实践背道而驰。
通过推断对更大范围的引用的非法赋值进行
从本质上讲,作用域是生命周期。更清楚的是,生命周期'a
是一个通用的生命周期参数,它可以在编译时根据调用位置在特定范围内进行专门化。
是实际需要的显式生命周期,以防止...错误?
不用谢。需要生命周期来防止错误,但需要显式的生命周期来保护不太健全的程序员所拥有的。
发布于 2015-07-24 19:52:19
让我们看一下下面的例子。
fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
x
}
fn main() {
let x = 12;
let z: &u32 = {
let y = 42;
foo(&x, &y)
};
}
在这里,显式的生命周期很重要。这是因为foo
的结果与它的第一个参数('a
)具有相同的生命周期,所以它可能比第二个参数更长。这是由foo
签名中的生命周期名称表示的。如果您将调用中的参数切换为foo
,编译器将会抱怨y
的生存时间不够长:
error[E0597]: `y` does not live long enough
--> src/main.rs:10:5
|
9 | foo(&y, &x)
| - borrow occurs here
10 | };
| ^ `y` dropped here while still borrowed
11 | }
| - borrowed value needs to live until here
发布于 2015-07-25 18:47:31
以下结构中的生存期注释:
struct Foo<'a> {
x: &'a i32,
}
指定Foo
实例的生存期不应超过它所包含的引用(x
字段)。
您在“生锈”一书中遇到的示例并没有说明这一点,因为f
和y
变量同时超出了范围。
一个更好的例子是:
fn main() {
let f : Foo;
{
let n = 5; // variable that is invalid outside this block
let y = &n;
f = Foo { x: y };
};
println!("{}", f.x);
}
现在,f
确实比f.x
所指向的变量存活得更久。
https://stackoverflow.com/questions/31609137
复制相似问题