Rust 即使在存在`&;的情况下,我是否可以强制将生存期参数设置为较短的生存期(合理);mut T`?
我正试图用生锈的父指针制作一棵树。节点结构上的一个方法给了我生存期问题。下面是一个简单的示例,其中明确地编写了生命周期,以便我能够理解它们:Rust 即使在存在`&;的情况下,我是否可以强制将生存期参数设置为较短的生存期(合理);mut T`?,rust,lifetime,Rust,Lifetime,我正试图用生锈的父指针制作一棵树。节点结构上的一个方法给了我生存期问题。下面是一个简单的示例,其中明确地编写了生命周期,以便我能够理解它们: 使用core::mem::transmute; pub结构LogNode LogNode(self:&'a mut LogNode{ LogNode(部分(自身)) } pub fn蜕变的孩子{ 不安全{ LogNode(一些( transmute::,&'a mut LogNode。如果我将可变引用更改为共享引用,那么听起来可变引用是一个问题,因为&mu
使用core::mem::transmute;
pub结构LogNode LogNode(self:&'a mut LogNode{
LogNode(部分(自身))
}
pub fn蜕变的孩子{
不安全{
LogNode(一些(
transmute::,&'a mut LogNode
。如果我将可变引用更改为共享引用,那么听起来可变引用是一个问题,因为&mut T T
在T
上是不变的(而&T
是协变的)。我猜LogNode
中的可变引用冒泡,使LogNode
自身在其生存期参数中保持不变
但我不明白为什么这是真的,直觉上它感觉使用LogNode是完美的。答案是#3:child
不能在安全的锈迹中实现,而transmuted\u child
是不可靠的。下面是一个使用transmuted\u child
的程序(没有其他不安全的代码)要导致SEG故障,请执行以下操作:
fn oops(arg: &mut LogNode<'static>) {
let mut short = LogNode(None);
let mut child = arg.transmuted_child();
if let Some(ref mut arg) = child.0 {
arg.0 = Some(&mut short);
}
}
fn main() {
let mut node = LogNode(None);
oops(&mut node);
println!("{:?}", node);
}
fn oops(arg:&mut LogNode要理解为什么不可变版本有效,而可变版本不可靠(如所述),我们必须讨论
Rust通常没有子类型。值通常具有唯一的类型。但是,Rust有子类型的一个地方是使用寿命。如果'a:'b
(读'a
比'b
长),然后,例如,&'at
是&'bt
的一个子类型,直觉上是因为更长的生命周期可以被视为更短的生命周期
方差是子类型传播的方式。如果A
是B
的子类型,并且我们有一个泛型Foo
,Foo
可能是Foo
的子类型,反之亦然,或者两者都不是。在第一种情况下,如果子类型的方向保持不变,Foo
就T而言是协变的
。在第二种情况下,当方向反转时,它被称为逆变,在第三种情况下,它被称为不变
对于这种情况,相关类型是&'at
和&'a mut
。两者在'a
中都是协变的(因此寿命较长的引用可以强制为寿命较短的引用)。&'a T
在T
中是协变的,但&'a mut
在T
中是不变的
fn evil_feeder(pet: &mut Animal) {
let spike: Dog = ...;
// `pet` is an Animal, and Dog is a subtype of Animal,
// so this should be fine, right..?
*pet = spike;
}
fn main() {
let mut mr_snuggles: Cat = ...;
evil_feeder(&mut mr_snuggles); // Replaces mr_snuggles with a Dog
mr_snuggles.meow(); // OH NO, MEOWING DOG!
}
这一点的原因在Nomicon(上面链接)中有解释,因此我将向您展示其中给出的(稍微简化的)示例。Trentcl的代码是一个工作示例,说明了如果&一个mut T
在T
中是协变的,会出现什么问题
fn evil_feeder(pet: &mut Animal) {
let spike: Dog = ...;
// `pet` is an Animal, and Dog is a subtype of Animal,
// so this should be fine, right..?
*pet = spike;
}
fn main() {
let mut mr_snuggles: Cat = ...;
evil_feeder(&mut mr_snuggles); // Replaces mr_snuggles with a Dog
mr_snuggles.meow(); // OH NO, MEOWING DOG!
}
那么为什么不可变版本的child
有效,而可变版本无效呢?在不可变版本中,LogNode
包含对LogNode
的不可变引用,因此通过生存期和类型参数中的协方差,LogNode
在其生存期参数中是协变的。如果'a:'b
,则enLogNode
我们有self:&'a LogNode
)因此,由于LogNode
是协变的,LogNode
。此外,不可变引用中的协变再次允许&一个LogNode
在'n
中是不协变的。这里的方差归结为和n个mut LogNode
的方差,不能强制为&一个mut LogNodeI接受Trentc的答案,因为它帮助我认识到如何解决我的问题,但是你的回答也非常有用!谢谢你用我的代码解释。