这个语法 (<T=Self>) 是什么意思?何时使用它?

5
我有时会看到像<T=Self>T=()这样的通用结构/特性。我怀疑这与通用类型T的默认类型有关。但我找不到任何文档资料。
我的问题是:
  • 它真正意味着什么?
  • 有哪些可能的变化(也许像<T=Self: 'static>这样疯狂)?
  • 它何时有用(例如示例)?
2个回答

6

这个语法可以用于两种情况:默认类型参数和关联类型。为了看到差异和使用方法,让我们来看一下 Add 特性,用于定义 + 操作符:

pub trait Add<RHS = Self> {
    type Output;
    fn add(self, rhs: RHS) -> Self::Output;
}

默认类型参数

在这里,类型参数 RHS 有一个默认值: Self。这意味着,每当我使用此 trait 时,如果省略该参数,则该类型参数的值将默认为 Self。例如:

impl Add for Foo { /* ... */ }

等同于

impl Add<Foo> for Foo { /* ... */ }

同样地,
fn foo<T>(t: T) where T: Add { /* ... */ }

是相同的。
fn foo<T>(t: T) where T: Add<T> { /* ... */ }

关联类型

特质Add还有一个关联类型:Output。该类型由特质的实现进行选择。

这样做的��因是,在输入类型相同的情况下,实现不同输出类型的Add毫无意义:一旦知道了SelfRHS,就无法选择Output类型。

例如,在迭代器中,当你遍历容器时,无法选择生成的值的类型,因此它是一个关联类型。

可以通过使用Foo = Bar语法在where子句中为关联类型选择一个值。例如:

fn foo<I>(i: I) where I: Iterator<Item=u8> { /* ... */ }

该函数可以在任何产生u8值的迭代器上工作。

总结

在通用构造的定义中使用Foo=Bar语法允许您为类型参数设置默认值,在where子句中使用时,它允许您匹配关联类型的值。

没有可能出现像Foo = Bar : Baz这样的变化或类似的事情。


非常好的答案!谢谢 :) - Christoph

2
这种语法与关联类型一起使用。有时,您希望避免每次都指定变量,并希望它们由类型指定,因此您可以使用以下语法:
trait Operation {
    type Input: Display;
    type Output: Display;

    fn do_it(&self, g: Self::Input) -> Self::Output;
}

相对于

trait Operation<T: Display, V: Display> {    
    fn do_it(&self, g: T) -> V;
}

在这种情况下,当你声明一个使用Operation的函数时,你可以简单地写成fn take_operation<O: Operation>(operation: O, input: O::Input) -> O::Output,而不是fn take_operation<T: Display, V: Display, O: Operation<T, V>>(operation: O, input: T) -> V
在某些情况下,你想限制你接受的类型范围。例如,当你想将输入类型限制为u32时,通常会写成fn take_operation<V: Display, O: Operation<u32, V>>(operation: O, input: u32) -> V。然而,使用关联类型,你将以不同的方式指定约束:fn take_operation<O: Operation<Input=u32>>(operation: O, input: u32) -> O::Output

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