这显然是完全安全的
对于人类来说显而易见的并不总是对编译器来说显而易见;有时编译器没有人类聪明(但它更加警觉!)。
在这种情况下,只要启用了非词法生命周期,您的原始代码就可以编译:
#![feature(nll)]
struct Foo<'a> {
boo: Option<&'a mut String>,
}
fn main() {
let mut foo = Foo { boo: None };
{
let mut string = "Hello".to_string();
foo.boo = Some(&mut string);
foo.boo.unwrap().push_str(", I am foo!");
foo.boo = None;
}
}
这是因为foo
在string
超出作用域后将无法使用,而不是因为你将值设置为None
。在最内部作用域之后尝试打印值仍然会导致错误。
是否可能有一个包含对比结构体生命周期更短的值的引用的结构体?
Rust借用系统的目的是确保持有引用的事物不要比所引用的项目存在更长的生命周期。
非词法生命周期后
也许可以,只要在引用不再有效后不再使用它。例如,下面的代码可以正常工作:
#![feature(nll)]
struct Foo<'a> {
boo: Option<&'a mut String>,
}
fn main() {
let mut foo = Foo { boo: None };
let mut string1 = "Hello".to_string();
foo.boo = Some(&mut string1);
let mut string2 = "Goodbye".to_string();
foo.boo = Some(&mut string2);
}
非词法生命周期之前
不行。借用检查器并不聪明到能够判断你是否会在引用失效后继续使用它。它过于保守。
在这种情况下,你遇到的问题是生命周期被表示为类型的一部分。换句话说,通用生命周期参数 'a
已经被填充为具体的生命周期值,涵盖了 string
存活的行。然而,foo
的生命周期比那些行更长,因此出现了错误。
编译器不会考虑你的代码执行了哪些操作;一旦它看到你使用了特定的生命周期作为参数,那么它就是那样的。
我通常会采取的解决方法是将类型分成需要引用和不需要引用的两个部分:
struct FooCore {
size: i32,
}
struct Foo<'a> {
core: FooCore,
boo: &'a mut String,
}
fn main() {
let core = FooCore { size: 42 };
let core = {
let mut string = "Hello".to_string();
let foo = Foo { core, boo: &mut string };
foo.boo.push_str(", I am foo!");
foo.core
};
}
请注意,这将消除对
Option
的需求-您的类型现在告诉您字符串是否存在。
另一种解决方案是在设置字符串时映射整个类型。在这种情况下,我们会使用整个变量并通过更改生命周期来更改类型:
struct Foo<'a> {
boo: Option<&'a mut String>,
}
impl<'a> Foo<'a> {
fn set<'b>(self, boo: &'b mut String) -> Foo<'b> {
Foo { boo: Some(boo) }
}
fn unset(self) -> Foo<'static> {
Foo { boo: None }
}
}
fn main() {
let foo = Foo { boo: None };
let foo = {
let mut string = "Hello".to_string();
let mut foo = foo.set(&mut string);
foo.boo.as_mut().unwrap().push_str(", I am foo!");
foo.unset()
};
}
foo
的目的是什么? - Matthieu M.