借用Box <trait>内容如何工作?

时间:2017-01-16 18:27:48

标签: rust traits borrow-checker

我有this minimal example code

use std::borrow::BorrowMut;

trait Foo {}
struct Bar;
impl Foo for Bar {}

fn main() {
    let mut encryptor: Box<Foo> = Box::new(Bar);

    encrypt(encryptor.borrow_mut());
}

fn encrypt(encryptor: &mut Foo) { }

但它失败并出现此错误:

error: `encryptor` does not live long enough
  --> src/main.rs:11:1
   |
10 |     encrypt(encryptor.borrow_mut());
   |             --------- borrow occurs here
11 | }
   | ^ `encryptor` dropped here while still borrowed
   |
   = note: values in a scope are dropped in the opposite order they are created

#rustbeginners的善良人士发现我必须取消引用该框以获取内容,然后借用内容。 Like this

trait Foo {}
struct Bar;
impl Foo for Bar {}

fn main() {
    let mut encryptor: Box<Foo> = Box::new(Bar);

    encrypt(&mut *encryptor);
}

fn encrypt(encryptor: &mut Foo) { }

它有效,但我不明白。

为什么我需要先取消引用?想说什么错误?通常,在函数结束时删除值不是错误。

显然不仅仅是我不明白这是如何运作的; issue has been filed

1 个答案:

答案 0 :(得分:6)

让我们从允许代码工作的更改开始:

fn encrypt(encryptor: &mut (Foo + 'static)) { }

重要的区别是向特征对象添加了+ 'static - 优先需要parens。

重要的是要认识到are two lifetimes present in &Foo

  • 引用本身的生命周期:&'a Foo
  • 一个生命周期,表示特征摘要的具体值内的所有引用:&(Foo + 'b)

如果我正确地阅读了RFC,则由RFC 192引入,并且RFC 599指定了生命周期的合理默认值。在这种情况下,生命周期扩展如下:

fn encrypt(encryptor: &mut Foo) { }
fn encrypt<'a>(encryptor: &'a mut (Foo + 'a)) { }

在管道的另一端,我们有一个Box<Foo>。根据RFC的规则扩展,这变为Box<Foo + 'static>。当我们借用它并尝试将其传递给函数时,我们有一个方程式来解决:

  • 特质对象内的生命周期为'static
  • 该函数引用特征对象。
  • 引用的生命周期等于特征对象内引用的生命周期。
  • 因此,对特征对象的引用必须是'static。呃哦!

Box将在块的末尾被删除,因此它肯定不是静态的。

具有显式生存期的修复允许特征对象的引用的生命周期与特征对象内部内部的生命周期不同。

如果您需要支持具有内部引用的特征对象,则替代方法是执行以下操作:

fn encrypt<'a>(encryptor: &mut (Foo + 'a)) { }

这个解释的真正功劳goes to nikomatsakis and his comment on GitHub,我只是稍微扩展了一下。