Rust中明确的生命周期错误

4
我有一个Rust枚举想要使用,但是我收到了错误信息:
error: explicit lifetime bound required
numeric(Num),
        ~~~

所涉及的枚举类型:

所涉及的枚举类型:

enum expr{
   numeric(Num),
   symbol(String),
}

我不确定这里借用的是什么。我的意图是让 NumString 与包含的表达式具有相同的生命周期,以便我可以从函数中返回它们。

1个回答

8
错误信息有些误导性。Num是一个trait,它是一种动态大小的类型,因此你不能没有某种间接方式(引用或Box)就拥有它的值。原因很简单,只需问自己一个问题:枚举值expr必须具有多少字节大小?它肯定至少和String一样大,但Num呢?任意类型都可以实现这个trait,因此为了保证sound,expr必须具有无限大小!
因此,你只能使用traits作为某种指针类型:&Num或Box。指针总是有固定的大小,而trait对象是“fat”指针,在其中保存额外的信息以帮助方法分派。
另外,traits通常用作泛型类型参数的边界。因为泛型是单态化的,它们在编译后变成静态类型,因此它们的大小总是静态已知的,不需要指针。使用泛型应该是默认的方法,只有当你知道泛型无法满足你的需求时,才应该切换到trait对象。
以下是您类型定义的可能变体。使用泛型:
enum Expr<N: Num> {
    Numeric(N),
    Symbol(String)
}

通过引用使用Trait对象:

enum Expr<'a> {  // '
    Numeric(&'a Num + 'a),
    Symbol(String)
}

带有盒子的特性对象:

enum Expr {
    Numeric(Box<Num + 'static>),  // ' // I used 'static because numbers usually don't contain references inside them
    Symbol(String)
}

您可以在官方指南中了解更多关于泛型和特质的信息,不过目前它缺乏有关特质对象的信息。如果您有任何疑问,请随时询问。

更新

'a

enum Expr<'a> {  // '
    Numeric(&'a Num + 'a),
    Symbol(String)
}

它是一个生命周期参数。它定义了引用的生命周期和Numeric变量内部的特质对象的生命周期。 &'a Num + 'a是一种类型,您可以将其读作“引用后面的特质对象‘a’至少与其一样长,并且其中包含的引用也至少与其一样长”。也就是说,首先,您需要指定'a作为引用生命周期:&'a,其次,您需要指定特质对象内部的生命周期:Num + 'a。后者是必需的,因为特质可以为任何类型实现,包括其中包含引用的类型,因此您需要把这些引用的最小生命周期也放入特质对象类型中,否则对于特质对象的借用检查将不能正确工作。

使用Box时情况非常相似。Box<Num + 'static>是“堆分配的盒子内的特质对象,其中包含的引用至少与'static一样长”。Box类型是堆分配的拥有数据的智能指针。因为它拥有它持有的数据,所以它不像引用那样需要生命周期参数。但是,特质对象仍然可能包含其中的引用,这就是为什么仍然使用Num + 'a的原因;我只选择使用'static生命周期而不是添加另一个生命周期参数。这是因为数值类型通常很简单,其中没有包含引用,而且它等价于'static约束。当然,如果您想要,可以自由添加生命周期参数。

请注意,所有这些变体都是正确的:

&'a SomeTrait + 'a
&'a SomeTrait + 'static
Box<SomeTrait + 'a>  // '
Box<SomeTrait + 'static>

即使这样是正确的,其中 'a'b 是不同的生命周期参数:
&'a SomeTrait + 'b

尽管这很少有用,因为'b必须至少和'a一样长(否则特质对象的内部可能在其自身仍然存在时被使无效),所以您可以同样使用&'a SomeTrait + 'a


通用版本的使用方法很笨拙,因为实例化Symbol可能导致编译器无法推断出N的具体类型。此外,如果最终Expr发展成包含包含子表达式的变量,通用版本将无法扩展。我认为在一般情况下应首先考虑通用版本,但在这种情况下,我认为它不是正确的解决方案。此外,根据要求,将Numeric(N)替换为两个变量:Integer(i64)Float(f64)也足以避免装箱。 - Francis Gagné
谢谢,这真的很有帮助。不过我有一个问题,Numeric(&'a Num + 'a) 中的 aNumeric(Box<Num + 'static>) 中的 static 是做什么用的? - ragingSloth
@FrancisGagné,是的,你说得完全正确。我本来想加上这样的注释,但不知怎么就忘了。谢谢! - Vladimir Matveev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接