在 Rust 中,当对作为泛型参数传递的值进行装箱时,为什么需要"静态"生命周期绑定?



我正试图编写一个构造函数,它采用一个通过参数实现某种特征的泛型值,然后将其装箱(重点是用这些方框初始化一些东西,但下面的例子被简化了(:

struct Struct {}
trait Trait {}
impl Trait for Struct {}
fn f(arg: impl Trait) -> Box<dyn Trait> {
Box::new(arg)
}
fn main() {
let x = Struct {};
f(x);
}

在这里,编译器抱怨arg可能活得不够长。这对我来说非常有意义,因为arg的唯一要求是impl Trait,这意味着它实际上可能是实现特性的引用,在这种情况下,它无法安全装箱。

让我困惑的是以下解决方案,添加了一个'static绑定:

fn f(arg: impl Trait + 'static) -> Box<dyn Trait> {
Box::new(arg)
}

现在,它当然有效,但原则上,我们现在只能传递具有'static生存期的值。然而,编译器让我可以毫无问题地通过x

以下是我的问题,更具体地说:

  1. x不存在于堆栈中吗?为什么当arg具有'static生存期限制时,可以将其传递给f?这些界限只涉及引用的生存期吗
  2. 这个解决方案通常有效吗?或者我会面临编译器拒绝我的堆栈分配参数的情况吗
  3. 有没有更好的说法;任何包含Trait的类型,其中该类型不是引用

注意,1(的答案大多是"为什么Rust需要一个`';静态"此变量的生存期"?但我感到困惑的是,这是否是拳击辩论的惯用方式。


编辑:

现在我更好地理解了,我想知道在填充结构的情况下,修复编译器错误的惯用解决方案是什么:

struct OtherStruct {
x: Box<dyn Trait>,
}
impl OtherStruct {
fn new(arg: impl Trait) -> Self { // Does not compile
Self { x: Box::new(arg) }
}
}

到目前为止,我看到的唯一解决方案是1(向OtherStruct添加生存期参数(不太好(,向arg添加'static生存期绑定(我不确定这是否可以?(

您有几个误解。

x不存在于堆栈中吗?当arg有"static lifetime bound"时,为什么可以将其传递给f?这些界限只涉及引用的生存期吗?

在执行f(x)时,因为没有引用x,所以x的值移动到函数中,从而改变其寿命。如果您在调用f(x)后再次尝试使用x,Rust将无法编译您的代码并告诉您这一点。

至于+ 'static界。。。Box<dyn Trait>Box<dyn Trait + 'static>的简写,这就是编译器给您一个错误的原因。类型系统需要知道盒子里实现的生存期,这样它才能检查它。如果你愿意,你可以明确地给盒子一个不同的生存期:

fn f<'a>(arg: impl Trait + 'a) -> Box<dyn Trait + 'a> {
Box::new(arg)
}

最新更新