为什么Rust中的关联类型需要显式生命周期注释?

4

我正在处理一种无法像这样(缩小)触摸的特性:

// The associated version
trait Testable {
    type T;
    fn test_it(&self, x: Self::T) -> bool;
}

然后我会尝试用i32等类型的数据进行impl操作:

impl Testable for i32 {
    type T = &str;
    fn test_it(&self, x: Self::T) -> bool {
        x.is_empty()
    }
}

然而,我遇到了编译器错误:

type T = &str;
         ^ explicit lifetime name needed here

相关联的类型Self::T只是方法test_it的输入参数。为什么编译器要求我提供生命周期注释?

请注意,如果我将T更改为通用类型,例如:

// The generic version
trait Testable<T> {
    fn test_it(&self, x: T) -> bool;
}

impl Testable<&str> for i32 {
    fn test_it(&self, x: &str) -> bool {
        x.is_empty()
    }
}

这次代码编译无误。

问题在于:

(1) 为什么我必须在关联版本中提供生命周期注解,因为该类型仅出现在输入参数一侧?

(2) 为什么泛型版本被编译了?这两个版本之间是否存在深层区别?


你运行过 rustc --explain E0637 吗?这是绝对不被允许的。 - cafce25
@cafce25,你能进一步解释为什么这是不允许的吗?我已经阅读了关于E0637的文档,但我仍然不理解设计原因。 - Ireina
1
@Ireina,嗯,生命周期是类型泛型的一部分。如果不是因为Rust有时会提升这个要求,你总是需要指定它。在这种特殊情况下,Rust不会对规则做出例外,你必须指定生命周期。 - jthulhu
@BlackBeans 谢谢你。我知道 rust 经常需要在引用上注明生命周期。你能否进一步解释一下为什么泛型版本编译通过了而没有报错(这次为什么不需要生命周期注释)? - Ireina
@Ireina “生命周期消除”是一种使生命周期变为可选的机制,其在 rustnomicon 中有详细解释。 - jthulhu
1
我的猜测是,在第一种情况下,您无法放置任何生命周期注释使其编译。您将不得不更改特征以使其与 T =&str 一起工作,而在第二个版本中,您实际上可以放置生命周期注释,编译器也可以为您确定。 - isaactfa
1个回答

4
关键区别在于关联类型是由trait选择的,而泛型参数是由调用者选择的。因此,使用以下代码时:
impl Testable for i32 {
    type T = &str;
    fn test_it(&self, x: Self::T) -> bool {
        x.is_empty()
    }
}

编译器需要在不查看代码的其他部分的情况下了解有关 T 的所有内容。但是它无法做到:仅通过查看此代码,无法知道引用的生命周期(顺便提一下,这里唯一可行的生命周期是'static)。

另一方面,对于这段代码:

impl Testable<&str> for i32 {
    fn test_it(&self, x: &str) -> bool {
        x.is_empty()
    }
}

&str是一个不完整的类型,因为它缺少生命周期,但这没关系,因为该类型将在调用站点上填充(就像所有模板参数一样)。

&str 是一个不完整类型,因为它缺少生命周期,但这没问题,因为该类型将在调用时被填充(和所有模板参数一样)。


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