简体   繁体   English

为什么借用检查器抱怨这些不同切片的生命周期?

[英]Why does borrow checker complain about the lifetimes of these different slices?

Why, in the code below, does using an array slice work, but using a slice of a Vec doesn't?为什么,在下面的代码中,使用数组切片有效,但使用Vec的切片无效?

use rand::{rngs::adapter::ReadRng, RngCore};
use std::io::Read;

struct MyRng {
    rng: Box<dyn RngCore>,
}

pub fn main() {
    // Version 1: error
    //
    let data = Vec::<u8>::new();
    let data_slice = data.as_slice();

    // Version 2: works
    //
    // let data_slice = &[0_u8][..];

    // Version 3: error (!?!)
    //
    // let data = [0_u8];
    // let data_slice = &data[..];

    let read = Box::new(data_slice) as Box<dyn Read>;
    let rng = Box::new(ReadRng::new(read));

    // With this commented out, all versions work.
    MyRng { rng };
}

There are a few things that puzzle me:有几件事让我感到困惑:

  • What's the difference between the three approaches, if all are in the same scope?如果都在同一个 scope 中,这三种方法有什么区别?
  • The error says that data is dropped while borrowed, but points to the end of the scope - isn't everything dropped by then?该错误表示data在借用时被丢弃,但指向 scope 的末尾 - 到那时不是所有东西都丢弃了吗?
  • Why if I remove the MyRng instantiation, everything works fine?为什么如果我删除MyRng实例化,一切正常?

The Rust Reference on Lifetime Elision: Rust 终身省略参考:

If the trait has no lifetime bounds, then the lifetime is inferred in expressions and is 'static outside of expressions.如果特征没有生命周期边界,则生命周期在表达式中推断,并且在表达式之外是'static的”。

So by default boxed trait objects get a 'static bound.因此,默认情况下,盒装 trait 对象获得一个'static绑定”。 So this struct:所以这个结构:

struct MyRng {
    rng: Box<dyn RngCore>,
}

Actually expands to this:实际上扩展为:

struct MyRng {
    rng: Box<dyn RngCore + 'static>,
}

Which forces you to produce either an owned type or a 'static reference in order to satisfy the bound.这会迫使您生成拥有的类型或'static引用”以满足界限。 However, you can opt out of the implicit 'static bound entirely by making your struct generic, after which all the different versions of the code compile:但是,您可以通过使您的结构通用来完全退出隐式'static绑定,然后编译所有不同版本的代码:

use rand::{rngs::adapter::ReadRng, RngCore};
use std::io::Read;

struct MyRng<'a> {
    rng: Box<dyn RngCore + 'a>,
}

pub fn main() {
    // Version 1: now works
    let data = Vec::<u8>::new();
    let data_slice = data.as_slice();
    let read = Box::new(data_slice) as Box<dyn Read>;
    let rng = Box::new(ReadRng::new(read));
    let my_rng = MyRng { rng };

    // Version 2: still works
    let data_slice = &[0_u8][..];
    let read = Box::new(data_slice) as Box<dyn Read>;
    let rng = Box::new(ReadRng::new(read));
    let my_rng = MyRng { rng };

    // Version 3: now works
    let data = [0_u8];
    let data_slice = &data[..];
    let read = Box::new(data_slice) as Box<dyn Read>;
    let rng = Box::new(ReadRng::new(read));
    let my_rng = MyRng { rng };
}

playground 操场


To answer your individual questions more directly:要更直接地回答您的个人问题:

What's the difference between the three approaches, if all are in the same scope?如果都在同一个 scope 中,这三种方法有什么区别?

Scope and lifetimes aren't the same thing, but the main difference between the 3 approaches is that approach #2 creates a static slice. Scope 和生命周期不是一回事,但 3 种方法之间的主要区别在于方法 #2 创建了 static 切片。 When you hardcode some &T reference into your code without it referring to any data owned by any variable then it gets written into the read-only segment of the binary and gets a 'static lifetime.当您将一些&T引用硬编码到您的代码中而不引用任何变量拥有的任何数据时,它会被写入二进制文件的只读段并获得'static生命周期”。

The error says that data is dropped while borrowed, but points to the end of the scope - isn't everything dropped by then?该错误表示数据在借用时被丢弃,但指向 scope 的末尾 - 到那时不是所有东西都丢弃了吗?

Yes, but your type, by definition, requires the passed value to be bounded by a 'static lifetime, and since approaches #1 and #3 do not produce such values the compiler rejects the code.是的,但是根据定义,您的类型要求传递的值受'static生命周期的限制,并且由于方法 #1 和 #3 不会产生这样的值,因此编译器会拒绝该代码。

Why if I remove the MyRng instantiation, everything works fine?为什么如果我删除MyRng实例化,一切正常?

Because there's nothing wrong with the definition of your MyRng struct, only when you try to instantiate it incorrectly does the compiler complain.因为您的MyRng结构的定义没有任何问题,只有当您尝试错误地实例化它时,编译器才会抱怨。

[0_u8] is a constant, so it undergoes rvalue static promotion , allowing references to it to have a static lifetime, so it won't be dropped. [0_u8]是一个常数,因此它经历了右值 static 提升,允许对它的引用具有 static 生命周期,因此它不会被丢弃。 Your code fails because you have a slice that borrows the local variable data yet tries to create a MyRng variable from it.您的代码失败,因为您有一个借用局部变量data的切片,但尝试从中创建一个MyRng变量。

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

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