[英]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:有几件事让我感到困惑:
data
is dropped while borrowed, but points to the end of the scope - isn't everything dropped by then?该错误表示data
在借用时被丢弃,但指向 scope 的末尾 - 到那时不是所有东西都丢弃了吗?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 };
}
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.