我正试图编写一个构造函数,它采用一个通过参数实现某种特征的泛型值,然后将其装箱(重点是用这些方框初始化一些东西,但下面的例子被简化了(:
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
。
以下是我的问题,更具体地说:
x
不存在于堆栈中吗?为什么当arg
具有'static
生存期限制时,可以将其传递给f
?这些界限只涉及引用的生存期吗- 这个解决方案通常有效吗?或者我会面临编译器拒绝我的堆栈分配参数的情况吗
- 有没有更好的说法;任何包含
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)
}