简体   繁体   English

如何借用Box <Trait> 内容有效吗?

[英]How does borrowing Box<Trait> contents work?

I have 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) { }

but it fails with this error: 但它失败了这个错误:

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

The kind people at #rustbeginners found that I have to dereference the box to get the contents, and then borrow the contents. #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) { }

It works, but I don't understand it. 它有效,但我不明白。

Why do I need to dereference first? 为什么我需要先取消引用? What is the error trying to say? 想说什么错误? Normally it isn't an error that a value is dropped at the end of the function. 通常,在函数结束时删除值不是错误。


Apparently it's not just me who doesn't understand how this works; 显然不只是我不明白这是如何运作的; an issue has been filed . 已经提出了一个问题

Let's start with a change that allows the code to work: 让我们从允许代码工作的更改开始:

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

The important difference is the addition of + 'static to the trait object - the parens are just needed for precedence. 重要的区别是向特征对象添加了+ 'static - 优先需要parens。

The important thing to recognize is that there are two lifetimes present in &Foo : 需要认识到的重要一点是&Foo中存在两个生命周期

  • a lifetime for the reference itself: &'a Foo 参考本身的一生: &'a Foo
  • a lifetime that represents all the references inside the concrete value that the trait abstracts: &(Foo + 'b) . 表示特征抽象的具体值内所有引用的生命周期: &(Foo + 'b)

If I'm reading the RFCs correctly, this was introduced by RFC 192 , and RFC 599 specified reasonable defaults for the lifetimes. 如果我正确地读取RFC,这是由RFC 192引入的, RFC 599指定了生命周期的合理默认值。 In this case, the lifetimes should expand like: 在这种情况下,生命周期应该扩展如下:

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

On the other end of the pipe, we have a Box<Foo> . 在管道的另一端,我们有一个Box<Foo> Expanded by the rules of the RFC, this becomes Box<Foo + 'static> . 扩展了RFC的规则,这就变成了Box<Foo + 'static> When we take a borrow of it, and try to pass it to the function, we have an equation to solve: 当我们借用它并尝试将其传递给函数时,我们有一个等式来解决:

  • The lifetime inside the trait object is 'static . 特征对象内的生命周期是'static
  • The function takes a reference to a trait object. 该函数接受对特征对象的引用。
  • The lifetime of the reference equals the lifetime of references inside the trait object. 引用的生命周期等于特征对象内引用的生命周期。
  • Therefore, the reference to the trait object must be 'static . 因此,对特征对象的引用必须是'static Uh oh! 哦哦!

The Box will be dropped at the end of the block so it certainly isn't static. Box将在块的末尾被删除,因此它肯定不是静态的。

The fix with explicit lifetimes allows the lifetime of the reference to the trait object to differ from the lifetime of the references inside the trait object. 具有明确的寿命的修复程序允许参考性状对象的生命周期从性状对象内部的参考文献的寿命不同。

If you needed to support a trait object with internal references, an alternate is to do something like: 如果您需要支持具有内部引用的特征对象,则替代方法是执行以下操作:

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

True credit for this explanation goes to nikomatsakis and his comment on GitHub , I just expanded it a bit. 这个解释真正归功于nikomatsakis和他对GitHub的评论 ,我只是稍微扩展了一下。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM