Rust 生命周期的问题:impl 使用匿名生命周期而函数使用 <'a>,更改生命周期以匹配会导致错误
Trouble with Rust lifetimes: impl uses anonymous lifetime and function uses <'a>, changing the lifetimes to match leads to an error
您可以 运行 代码段 here。我删除了结构中一堆不相关的函数和字段,使事情更容易分析。
#[derive(Debug)]
pub struct Turtle<'a>{
children: Vec<&'a Turtle<'a>>,
}
impl Turtle<'_>{
pub fn new() -> Turtle<'static> {
Turtle {children: Vec::new()}
}
pub fn add_child<'a>(&self, t: &'a Turtle<'a>) {
&self.children.push(t);
}
}
错误是
|
11 | &self.children.push(t);
| ^ lifetime mismatch
|
= note: expected reference `&Turtle<'_>`
found reference `&Turtle<'a>`
note: the lifetime `'a` as defined on the method body at 10:22...
--> src/lib.rs:10:22
|
10 | pub fn add_child<'a>(&self, t: &'a Turtle<'a>) {
| ^^
note: ...does not necessarily outlive the lifetime `'_` as defined on the impl at 6:13
--> src/lib.rs:6:13
|
6 | impl Turtle<'_>{
| ^^
问题似乎在于,由于 impl 具有匿名生命周期,&self 具有 Turtle<'_> 类型,因此 self.children 具有匿名生命周期,这意味着 push 需要一个 Turtle<'_>。我想出了 2 个想法来解决这个问题,即要么将 impl 更改为 <'a>,要么将参数 t 的生命周期更改为 <'_>,但都没有用。我知道如何确保单个函数的生命周期是正确的,但是当涉及到各种函数、结构和 impl 都连接在一起时,事情就开始变得不清楚了。
您的结构需要一个生命周期,您已选择将其称为“a”。那个生命然后被“给予”或“分享”self.children。稍后,您为匿名生命周期实现您的结构,这是结构定义声明 self.children 也必须共享的生命周期。但是,您的“new”函数意味着创建具有“static”生命周期的 self.children(并且“static != ‘_ 因为 ‘_ 可能比 ‘static’短)。此外,您的 add child 方法需要一个(貌似)完全独立的生命周期,您也将其称为“a”(仅仅因为您将其称为“a”并不会使它与您在结构定义中命名的“a”相同)。尝试创建一个采用类型而不是生命周期(例如 T 或 V)的新结构?如果两者都没有边界,那么它们将基本相等。这同样适用于生命周期。
真正的解决办法在于匹配你的生命周期。由于您的结构的自引用性质,您不能使用匿名生命周期,因为编译器需要知道在添加子项时生命周期匹配。现在编译下面的内容。请注意使用 Self 来推断创建时的生命周期 <'a> 。您也可以使用 Turtle<'a>,但我个人会考虑使用 Self 更容易,因为它避免了额外的生命周期引用。此外,为了使您的 add_child 方法起作用,对“self”的引用需要是可变的(参见 &mut self)。这是因为您正在修改 self.children 的内容,因此改变了结构。
请注意,这将适用于“任何”生命周期,无论您将其称为“a”、“z”还是其他名称。关键是编译器可以推断出所涉及的所有内容的生命周期都是匹配的。
#[derive(Debug)]
pub struct Turtle<'a> {
children: Vec<&'a Turtle<'a>>,
}
impl<'a> Turtle<'a> {
pub fn new() -> Self {
Self { children: Vec::new() }
}
pub fn add_child(&mut self, t: &'a Turtle<'a>) {
self.children.push(t);
}
}
您可以 运行 代码段 here。我删除了结构中一堆不相关的函数和字段,使事情更容易分析。
#[derive(Debug)]
pub struct Turtle<'a>{
children: Vec<&'a Turtle<'a>>,
}
impl Turtle<'_>{
pub fn new() -> Turtle<'static> {
Turtle {children: Vec::new()}
}
pub fn add_child<'a>(&self, t: &'a Turtle<'a>) {
&self.children.push(t);
}
}
错误是
|
11 | &self.children.push(t);
| ^ lifetime mismatch
|
= note: expected reference `&Turtle<'_>`
found reference `&Turtle<'a>`
note: the lifetime `'a` as defined on the method body at 10:22...
--> src/lib.rs:10:22
|
10 | pub fn add_child<'a>(&self, t: &'a Turtle<'a>) {
| ^^
note: ...does not necessarily outlive the lifetime `'_` as defined on the impl at 6:13
--> src/lib.rs:6:13
|
6 | impl Turtle<'_>{
| ^^
问题似乎在于,由于 impl 具有匿名生命周期,&self 具有 Turtle<'_> 类型,因此 self.children 具有匿名生命周期,这意味着 push 需要一个 Turtle<'_>。我想出了 2 个想法来解决这个问题,即要么将 impl 更改为 <'a>,要么将参数 t 的生命周期更改为 <'_>,但都没有用。我知道如何确保单个函数的生命周期是正确的,但是当涉及到各种函数、结构和 impl 都连接在一起时,事情就开始变得不清楚了。
您的结构需要一个生命周期,您已选择将其称为“a”。那个生命然后被“给予”或“分享”self.children。稍后,您为匿名生命周期实现您的结构,这是结构定义声明 self.children 也必须共享的生命周期。但是,您的“new”函数意味着创建具有“static”生命周期的 self.children(并且“static != ‘_ 因为 ‘_ 可能比 ‘static’短)。此外,您的 add child 方法需要一个(貌似)完全独立的生命周期,您也将其称为“a”(仅仅因为您将其称为“a”并不会使它与您在结构定义中命名的“a”相同)。尝试创建一个采用类型而不是生命周期(例如 T 或 V)的新结构?如果两者都没有边界,那么它们将基本相等。这同样适用于生命周期。
真正的解决办法在于匹配你的生命周期。由于您的结构的自引用性质,您不能使用匿名生命周期,因为编译器需要知道在添加子项时生命周期匹配。现在编译下面的内容。请注意使用 Self 来推断创建时的生命周期 <'a> 。您也可以使用 Turtle<'a>,但我个人会考虑使用 Self 更容易,因为它避免了额外的生命周期引用。此外,为了使您的 add_child 方法起作用,对“self”的引用需要是可变的(参见 &mut self)。这是因为您正在修改 self.children 的内容,因此改变了结构。
请注意,这将适用于“任何”生命周期,无论您将其称为“a”、“z”还是其他名称。关键是编译器可以推断出所涉及的所有内容的生命周期都是匹配的。
#[derive(Debug)]
pub struct Turtle<'a> {
children: Vec<&'a Turtle<'a>>,
}
impl<'a> Turtle<'a> {
pub fn new() -> Self {
Self { children: Vec::new() }
}
pub fn add_child(&mut self, t: &'a Turtle<'a>) {
self.children.push(t);
}
}