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

Dan*_*ker 12 traits rust borrow-checker

我有这个最小的示例代码:

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) { }
Run Code Online (Sandbox Code Playgroud)

但它失败了这个错误:

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
Run Code Online (Sandbox Code Playgroud)

#rustbeginners的善良人士发现我必须取消引用该框以获取内容,然后借用内容.像这样:

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) { }
Run Code Online (Sandbox Code Playgroud)

它有效,但我不明白.

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


显然不只是我不明白这是如何运作的; 已经提出了一个问题.

She*_*ter 6

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

fn encrypt(encryptor: &mut (Foo + 'static)) { }
Run Code Online (Sandbox Code Playgroud)

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

认识到最重要的事情是,有2个寿命呈现&Foo:

  • 参考本身的生命周期: &'a Foo
  • 表示特征抽象的具体值内所有引用的生命周期:&(Foo + 'b).

如果我正确地读取RFC,这是由RFC 192引入的,RFC 599指定了生命周期的合理默认值.在这种情况下,生命周期应该扩展如下:

fn encrypt(encryptor: &mut Foo) { }
fn encrypt<'a>(encryptor: &'a mut (Foo + 'a)) { }
Run Code Online (Sandbox Code Playgroud)

在管道的另一端,我们有一个Box<Foo>.通过RFC的规则扩展,这变成了Box<Foo + 'static>.当我们借用它并尝试将其传递给函数时,我们有一个等式来解决:

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

Box将在块的结尾被丢弃所以它肯定不是一成不变的.

具有明确的寿命的修复程序允许基准的寿命该性状对象从引用的寿命不同内部性状对象.

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

fn encrypt<'a>(encryptor: &mut (Foo + 'a)) { }
Run Code Online (Sandbox Code Playgroud)

这个解释真正归功于nikomatsakis和他对GitHub的评论,我只是稍微扩展了一下.