Dan*_*ker 3 lifetime rust borrow-checker
Rust生活再次让我困惑.我试图将一个可变引用返回给我拥有的盒装对象.这是我的问题简化:
pub trait Foo {
fn foo(&self);
}
pub struct Bar {
foo: Option<Box<Foo>>,
}
impl Bar {
pub fn foo(&mut self) -> &mut Box<Foo> {
let foo_ref = self.foo.as_mut();
foo_ref.unwrap()
}
pub fn set_foo(&mut self, value: Box<Foo>) {
self.foo = Some(value);
}
}
Run Code Online (Sandbox Code Playgroud)
我得到这些错误,我真的不明白:
Compiling testproject v0.0.1 (file:///home/virtlink/projects/orion/testproject)
src/lib.rs:15:17: 15:25 error: cannot infer an appropriate lifetime due to conflicting requirements
src/lib.rs:15 foo_ref.unwrap()
^~~~~~~~
src/lib.rs:15:9: 15:25 note: first, the lifetime cannot outlive the method call at 15:8...
src/lib.rs:15 foo_ref.unwrap()
^~~~~~~~~~~~~~~~
src/lib.rs:15:9: 15:16 note: ...so that method receiver is valid for the method call
src/lib.rs:15 foo_ref.unwrap()
^~~~~~~
src/lib.rs:13:44: 16:6 note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the block at 13:43...
src/lib.rs:13 pub fn foo(&mut self) -> &mut Box<Foo> {
src/lib.rs:14 let foo_ref = self.foo.as_mut();
src/lib.rs:15 foo_ref.unwrap()
src/lib.rs:16 }
src/lib.rs:15:9: 15:25 note: ...so that expression is assignable (expected `&mut Box<Foo>`, found `&mut Box<Foo>`)
src/lib.rs:15 foo_ref.unwrap()
^~~~~~~~~~~~~~~~
error: aborting due to previous error
Could not compile `testproject`.
Run Code Online (Sandbox Code Playgroud)
我不知道如何解决这个问题.
Chr*_*gan 10
这是一个终身省略的情况,默认对象以痛苦的隐形方式限制回火.
错误是完全不透明的,这是不好的.如果.as_mut().unwrap()用可比较的match声明替换:
match self.foo {
Some(ref mut foo) => foo,
None => panic!(),
}
Run Code Online (Sandbox Code Playgroud)
事情变得更加清晰:
a.rs:13:34: 13:37 error: mismatched types:
expected `&mut Box<Foo>`,
found `&mut Box<Foo>`
(lifetime mismatch) [E0308]
a.rs:13 Some(ref mut foo) => foo,
^~~
a.rs:11:44: 16:6 note: the anonymous lifetime #1 defined on the block at 11:43...
a.rs:11 pub fn foo(&mut self) -> &mut Box<Foo> {
a.rs:12 match self.foo {
a.rs:13 Some(ref mut foo) => foo,
a.rs:14 None => panic!(),
a.rs:15 }
a.rs:16 }
note: ...does not necessarily outlive the static lifetime
error: aborting due to previous error
Run Code Online (Sandbox Code Playgroud)
现在我们知道发生的事情是类型中某处的生命周期不匹配,&mut Box<Foo>匿名生命周期并不一定比静态生命周期长.这种类型有两种生命周期; 没有类型省略,那种类型是&'a mut Box<Foo + 'b>.请记住,对于特征对象,您仍需要指示特征对象可以持续多长时间,因此'b.在最常见的情况下,Box<Trait>相当于Box<Trait + 'static>,表示特征对象不能包含任何非静态引用.(如果没有这种保证,将违反内存安全性.)在结构定义中,'static以这种方式推断特征对象的生命周期.
但是,elided life in Box<Trait>并不总是被解释为'static.如果它包含在引用中,则所需的生命周期缩小到该值,即被&'a Box<Trait>解释为&'a Box<Trait + 'a>.
因此,您的方法的完全无删除签名实际上是这样的:
pub fn foo<'a>(&'a mut self) -> &'a mut Box<Foo + 'a>;
Run Code Online (Sandbox Code Playgroud)
现在为什么这不起作用我不清楚; 我&'a mut Box<Foo + 'static>原本以为(你有)可以被强迫给a &'a mut Box<Foo + 'a>,但显然事实并非如此; ,它可能是方差处理中的错误(拒绝应该合法的代码)或者可能不是,我不确定.我不明白为什么匿名生命#1应该需要比静态生命周期更长,这种错误感觉它就像处理生命周期一样.
无论如何,你真正想要的是返回一个&'a mut Box<Foo + 'static>.所以只要'static明确地写出来,所有都是hunky-dory:
pub fn foo(&mut self) -> &mut Box<Foo + 'static> {
self.foo.as_mut().unwrap()
}
Run Code Online (Sandbox Code Playgroud)
另一种解决方案是在定义中要求实现的类型Foo必须始终如此'static.然后Box<Foo + 'a>对于一个'a不一定那么伟大的人来说显然是胡说八道'static,并且它变得明智并且知道它必须是'static.(特征上的任何生命周期约束都会覆盖默认对象边界.)
您可以在RFC 599中阅读有关默认对象边界的更多信息.