关于rust:as_mut()。unwrap():由于需求冲突而无法推断寿命

as_mut().unwrap(): Cannot infer lifetime due to conflicting requirements

Rust的一生再次使我感到困惑。 我试图返回对我拥有的装箱对象的可变引用。 这是我简化的问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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);
    }
}

我收到这些错误,但我不太了解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   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`.

我不确定该如何解决。


这是一辈子淘汰的情况,默认对象以痛苦的看不见的方式限制了回火。

错误是完全不透明的,不好。如果用类似的match语句替换.as_mut().unwrap()

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

事情变得更加清晰:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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的某处的生命周期不匹配,匿名生命周期不一定会超过静态生命周期。这种类型有两个生命周期。没有类型省略,该类型为&'a mut Box。请记住,对于特征对象,您仍然需要指示特征对象可以持续多长时间,因此'b。在最常见的情况下,Box等效于Box,这表明特征对象不能包含任何非静态引用。 (如果没有此保证,则会违反内存安全性。)在您的结构定义中,以这种方式将trait对象的生存期推断为'static

但是,Box中的有效期并不总是解释为'static。如果将其包含在引用中,则所需的生存期将缩减为该生存期,即&'a Box被解释为&'a Box

因此,您的方法的完全无电子签名实际上是这样的:

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

现在,为什么不起作用,我不清楚。我本以为&'a mut Box(您拥有的)可以被强制为&'a mut Box,但是显然不是这种情况。我不确定这可能是差异处理中的错误(拒绝应合法的代码),也可能不是。我不知道为什么#1匿名生命周期必须要比静态生命周期长寿,这种错误感觉就像是在重新处理生命周期一样。

无论如何,您真正想要的是返回&'a mut Box。因此,只需明确地写出'static,一切都是笨拙的:

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

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

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