Rust 关联类型

示例

  • 当实现特征的类型和关联的类型之间存在一对一关系时,请使用关联的类型。

  • 有时也称为输出类型,因为这是我们将特征应用到该类型时赋予该类型的项。

创建

trait GetItems {
    type First;
//  ^ ~~~定义关联的类型。 
    type Last: ?Sized;
//           ^ ~~~~~~~~相关类型也可能受特征约束
    fn first_item(&self) -> &Self::First;
//                           ^ ~~~~~~~~~~~使用`Self ::`来指代相关的类型 
    fn last_item(&self) -> &Self::Last;
//                          ^ ~~~~~~~~~~相关类型可以用作函数输出...
    fn set_first_item(&mut self, item: Self::First);
//                                     ^ ~~~~~~~~~~~ ...输入,以及任何位置。
}

实施方式

impl<T, U: ?Sized> GetItems for (T, U) {
    type First = T;
    type Last = U;
//              ^ ~~分配关联的类型
    fn first_item(&self) -> &Self::First { &self.0 }
    fn last_item(&self) -> &Self::Last { &self.1 }
    fn set_first_item(&mut self, item: Self::First) { self.0 = item; }
}

impl<T> GetItems for [T; 3] {
    type First = T;
    type Last = T;
    fn first_item(&self) -> &T { &self[0] }
//                           ^您可以参考实际类型而不是`Self :: First`
    fn last_item(&self) -> &T { &self[2] }
    fn set_first_item(&mut self, item: T) { self[0] = item; }
}

引用关联的类型

如果我们确定类型可以在泛型中T实现GetItems,则可以简单地使用它T::First来获取关联的类型。

fn get_first_and_last<T: GetItems>(obj: &T) -> (&T::First, &T::Last) {
//                                               ^ ~~~~~~~~指关联类型
    (obj.first_item(), obj.last_item())
}

否则,您需要明确告知编译器该类型正在实现的特征

let array: [u32; 3] = [1, 2, 3];
let first: &<[u32; 3] as GetItems>::First = array.first_item();
//          ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ [u32; 3]可以实现多种特征,其中许多
//                                        它们提供“ First”关联类型。
//                                        thus the explicit "cast" is necessary here.
assert_eq!(*first, 1);

约束关联类型

fn clone_first_and_last<T: GetItems>(obj: &T) -> (T::First, T::Last)
    where T::First: Clone, T::Last: Clone
//  ^ ~~~~使用where子句按特征约束关联类型
{
    (obj.first_item().clone(), obj.last_item().clone())
}

fn get_first_u32<T: GetItems<First=u32>>(obj: &T) -> u32 {
//                          ^ ~~~~~~~~~~~约束相等类型
    *obj.first_item()
}