【Rust中级教程】1.16. 泛型trait:泛型(类型参数)trait、关联类型trait
1.16 泛型trait泛型类型参数trait、关联类型trait这篇文章以概念性和建议性的文字偏多需要你对泛型类型参数和关联类型有一定了解。1.16.1. trait的泛型方式trait的泛型方式有两种- 泛型类型参数。例:trait FooT- 关联类型。例trait Foo{type Bar;}两者的区别在于- 使用关联类型这种形式的效果就是对于指定类型的trait只有一个实现- 使用泛型参数类型则可以有多个实现这里有一个简单的建议可以的话尽量使用关联类型。1.16.2. 泛型类型参数trait泛型trait要求必须指定所有的泛型类型参数并重复写这些参数的约束(bounds)。这么写维护起来会难一些。比如说如果添加泛型类型参数到某个trait该trait的所有实现者都必须更新代码。这种形式还可能会导致针对给定的类型一个trait有多重实现的问题。编译器会更难推断你想要的到底是trait的哪个实例。有时候不得不调用类似FromIterator::u32::from_iter这样可以消除歧义的函数。这个特性有的时候也会是一个优点例如-impl PatialEqBookFormat for Book其中BookFormat就可以是不同的类型- 可以同时实现FromIteratorT和FromIteratorT where T:Clone1.16.3. 关联类型trait我们以一段代码为例trait Contains { type A; type B; //Updates syntax to refer to these new types generically fn contains(self, _: Self::A, _: Self::B) - bool; }使用关联类型- 编译器只需要知道实现trait的类型-约束(bound)可以完全位于trait本身不必重复使用- 未来再添加关联类型也不影响用户使用- 具体的类型会决定trait内关联类型的类型无需使用消除歧义的函数看个例子impl Contains for Container { // Specify what types A and B are. If the input type // is Container(i32, i32), the output types are determined // as i32 and i32. type A i32; type B i32; // Self::A and Self::B are also valid here. fn contains(self, number_1: i32, number_2: i32) - bool { (self.0 number_1) (self.1 number_2) } // Grab the first number. fn first(self) - i32 { self.0 } // Grab the last number. fn last(self) - i32 { self.1 } }这个例子写了为Container类型实现ContainstraitContainer类型的Containstrait中的关联类型通过type A i32;和type B i32;这两行代码决定不可以对多个目标(Target)类型来实现Dereftrait看一下Dereftrait的源代码pub trait Deref { type Target: ?Sized; fn deref(self) - Self::Target; }type Target: ?Sized;中的Target就是我们说的目标(Target)类型我们随便写一个Dereftrait的实现来说明一下use std::ops::Deref; struct Wrapper { value: String, } impl Deref for Wrapper { type Target String; fn deref(self) - Self::Target { self.value } }上面代码中Wrapper只能解引用为String。但如果你想让Wrapper同时解引用为String和strRust不允许你再实现Deref因为Target只能有一个具体类型。也就是说这么写是非法的use std::ops::Deref; struct Wrapper { value: String, } // 第一次实现 DerefTarget String impl Deref for Wrapper { type Target String; fn deref(self) - Self::Target { self.value } } // 这是非法的Rust 不允许对同一个类型 Wrapper 进行第二次 Deref 实现 impl Deref for Wrapper { type Target str; // 冲突Rust 不能推断哪个 Target 生效 fn deref(self) - Self::Target { self.value } }不可以使用多个Item来实现Iteratortrait其原因与不可以对多个目标(Target)类型来实现Dereftrait一样主要涉及关联类型的唯一性和Rust 编译器的推断规则。