3

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);
    }
}

我收到这些错误,我不太明白:

   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`.

我不知道如何解决这个问题。

4

1 回答 1

11

这是一个生命周期省略的情况,默认对象以一种痛苦的无形方式适得其反。

错误是完全不透明的,这是不好的。如果您将 替换为.as_mut().unwrap()可比较的match语句:

match self.foo {
    Some(ref mut foo) => foo,
    None => panic!(),
}

事情变得更清楚了:

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

现在我们知道正在发生的事情是类型中某处的生命周期不匹配,&mut Box<Foo>匿名生命周期不一定比静态生命周期长。这种类型有两个生命周期;没有类型省略,该类型是&'a mut Box<Foo + 'b>. 请记住,对于 trait 对象,您仍然需要指出 trait 对象可以持续多长时间,因此'b. 在最常见的情况下,Box<Trait>等价于Box<Trait + 'static>,表示特征对象不能包含任何非静态引用。(如果没有这个保证,就会违反内存安全。)在你的结构定义中,特征对象的生命周期是以'static这种方式推断出来的。

但是,省略的生命周期Box<Trait>并不总是被解释为'static。如果它包含在引用中,则所需的生命周期会缩小到该值,即被&'a Box<Trait>解释为&'a Box<Trait + 'a>.

因此,您的方法的完整无省略签名实际上是这样的:

pub fn foo<'a>(&'a mut self) -> &'a mut Box<Foo + 'a>;

现在为什么这不起作用我不清楚;我会认为 a &'a mut Box<Foo + 'static>(你有)可以被强制转换为 a &'a mut Box<Foo + 'a>,但显然情况并非如此;这可能是方差处理中的错误(拒绝应该合法的代码),也可能不是,我不确定。我不明白为什么匿名生命周期#1 应该比静态生命周期更长,这个错误感觉就像它正在处理生命周期。

无论如何,你真正想要的是返回一个&'a mut Box<Foo + 'static>. 所以只要'static明确地写出来,一切都很好:

pub fn foo(&mut self) -> &mut Box<Foo + 'static> {
    self.foo.as_mut().unwrap()
}

另一种解决方案是在定义中要求实现的类型Foo必须始终是'static. 那么对于不一定和 一样伟大Box<Foo + 'a>的人来说显然是胡说八道,并且它变得明智并且知道它必须是。(特征上的任何生命周期约束都会覆盖默认对象边界。)'a'static'static

您可以在RFC 599中阅读有关默认对象边界的更多信息。

于 2015-04-13T13:37:12.617 回答