首页 文章

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

提问于
浏览
12

我有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) { }

它有效,但我不明白 .

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


显然它's not just me who doesn't了解这是如何工作的;一个issue has been filed .

1 回答

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

    • 该函数接受对特征对象的引用 .

    • 引用的生命周期等于特征对象内引用的生命周期 .

    • 因此,对trait对象的引用必须是 'static . 哦哦!

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

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

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

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

    真正的信用这个解释goes to nikomatsakis and his comment on GitHub,我只是扩展了一下 .

相关问题