编译器建议我添加“静态生存期,因为参数类型的生存期可能不够长,但是我认为这不是我想要的" [英] The compiler suggests I add a 'static lifetime because the parameter type may not live long enough, but I don't think that's what I want
问题描述
我正在尝试实现类似于以下最小示例的内容:
I'm trying to implement something that looks like this minimal example:
trait Bar<T> {}
struct Foo<T> {
data: Vec<Box<Bar<T>>>,
}
impl<T> Foo<T> {
fn add<U: Bar<T>>(&mut self, x: U) {
self.data.push(Box::new(x));
}
}
由于Rust默认为(据我所知)所有权传递,因此我的心智模型认为这应该可行. add
方法拥有对象x
的所有权,并能够将其移动到Box
中,因为它知道完整类型U
(而不仅仅是特征Bar<T>
).移入Box
后,盒子内物品的寿命应与盒子的实际寿命联系在一起(例如,当pop()
离开矢量时,物体将被破坏).
Since Rust defaults to (as far as I can tell) pass-by-ownership, my mental model thinks this should work. The add
method takes ownership of object x
and is able to move this object into a Box
because it knows the full type U
(and not just trait Bar<T>
). Once moved into a Box
, the lifetime of the item inside the box should be tied to the actual lifetime of the box (e.g., when pop()
ed off the vector the object will be destroyed).
但是,很明显,编译器不同意(我肯定比我知道更多...),要求我考虑添加一个'static
生存期限定符(E0310).我有99%的肯定那不是我想要的,但是我不确定我应该做什么.
Clearly, however, the compiler disagrees (and I'm sure knows a bit more than I...), asking me to consider adding a 'static
lifetime qualifier (E0310). I am 99% sure that's not what I want, but I'm not exactly sure what I'm supposed to do.
为弄清我的想法并帮助您识别误解,我的思维模式来自C ++背景:
To clarify what I'm thinking and help identify misconceptions, my mental model, coming from a C++ background, is:
-
Box<T>
本质上是std::unique_ptr<T>
- 没有任何注释,如果
Copy
,则变量将按值传递,否则,将使用rvalue-reference - 带有参考注释的
&
大致为const&
,而&mut
大致为&
- 默认生存期为词法范围
Box<T>
is essentiallystd::unique_ptr<T>
- Without any annotations, variables are passed by value if
Copy
and rvalue-reference otherwise - With a reference annotation,
&
is roughlyconst&
and&mut
is roughly&
- The default lifetime is lexical scope
推荐答案
查看整个错误:
error[E0310]: the parameter type `U` may not live long enough
--> src/main.rs:9:24
|
8 | fn add<U: Bar<T>>(&mut self, x: U) {
| -- help: consider adding an explicit lifetime bound `U: 'static`...
9 | self.data.push(Box::new(x));
| ^^^^^^^^^^^
|
note: ...so that the type `U` will meet its required lifetime bounds
--> src/main.rs:9:24
|
9 | self.data.push(Box::new(x));
| ^^^^^^^^^^^
具体来说,编译器会让您知道某些任意类型U
可能包含引用,然后该引用可能变得无效:
Specifically, the compiler is letting you know that it's possible that some arbitrary type U
might contain a reference, and that reference could then become invalid:
impl<'a, T> Bar<T> for &'a str {}
fn main() {
let mut foo = Foo { data: vec![] };
{
let s = "oh no".to_string();
foo.add(s.as_ref());
}
}
那将是个坏消息.
您要'static
生命周期还是参数化生命周期取决于您的需求. 'static
生存期更易于使用,但有更多限制.因此,这是在结构或类型别名中声明 trait对象时的默认设置:
Whether you want a 'static
lifetime or a parameterized lifetime is up to your needs. The 'static
lifetime is easier to use, but has more restrictions. Because of this, it's the default when you declare a trait object in a struct or a type alias:
struct Foo<T> {
data: Vec<Box<dyn Bar<T>>>,
// same as
// data: Vec<Box<dyn Bar<T> + 'static>>,
}
但是,当作为参数使用时,特征对象使用 lifetime Elision 并获得唯一的生命期:
However, when used as an argument, a trait object uses lifetime elision and gets a unique lifetime:
fn foo(&self, x: Box<dyn Bar<T>>)
// same as
// fn foo<'a, 'b>(&'a self, x: Box<dyn Bar<T> + 'b>)
这两个东西需要匹配.
struct Foo<'a, T> {
data: Vec<Box<dyn Bar<T> + 'a>>,
}
impl<'a, T> Foo<'a, T> {
fn add<U>(&mut self, x: U)
where
U: Bar<T> + 'a,
{
self.data.push(Box::new(x));
}
}
或
struct Foo<T> {
data: Vec<Box<dyn Bar<T>>>,
}
impl<T> Foo<T> {
fn add<U>(&mut self, x: U)
where
U: Bar<T> + 'static,
{
self.data.push(Box::new(x));
}
}
这篇关于编译器建议我添加“静态生存期,因为参数类型的生存期可能不够长,但是我认为这不是我想要的"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!