1、在Trait定义中使用关联类型来指定占位类型.
关联类型(associated type)是Trait 中的类型占位符,它可以用于Trait的方法
签名中:
可以定义出包含某些类型的Trait,而在实现前无需知道这些类型是什么
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
fn main() {
println!("Hello World!");
}
关联类型与泛型的区别
泛型
每次实现Trait时标注类型
可以为一个类型多次实现某个Trait
(不同的泛型参数)
关联类型
无需标注类型
无法为单个类型多次实现某个Trait
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
pub trait Iterator2<T> {
fn next(&mut self) -> Option<T>;
}
struct Counter{}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
None
}
}
impl Iterator2<String> for Counter {
fn next(&mut self) -> Option<String> {
None
}
}
impl Iterator2<u32> for Counter {
fn next(&mut self) -> Option<u32> {
None
}
}
fn main() {
println!("Hello World!");
}
默认泛型参数和运算符重载
可以在使用泛型参数时为泛型指定-一个默认的具体类型。
语法: <PlaceholderType=ConcreteType>
这种技术常用于运算符重载(operator overloading)
Rust不允许创建自己的运算符及重载任意的运算符
但可以通过实现std::ops中列出的那些trait来重载一部分相应的运算符
use std::ops::Add;
#[derive(Debug,PartialEq)]
struct Point {
x:i32,
y:i32
}
impl Add for Point {
type Output = Point;
fn add(self, orther: Point) -> Point {
Point {
x: self.x + orther.x,
y: self.y + orther.y
}
}
}
fn main() {
assert_eq!(Point{x:1,y:0}+Point{x:2,y:3},
Point{x:3,y:3}
)
}
下面我们来做一个让毫米和米相加的例子
use std::ops::Add;
struct Millimeters(u32);
struct Meters(u32);
impl Add<Meters> for Millimeters {
type Output = Millimeters;
fn add(self, orther: Meters) -> Millimeters {
Millimeters(self.0 + (orther.0 * 1000))
}
}
fn main() {
}
默认泛型参数的主要应用场景
扩展一个类型而不破坏现有代码
完全限定语法( Fully Qualified Syntax)
如何调用同名方法
trait Pilot {
fn fly(&self);
}
trait Wizad {
fn fly(&self);
}
struct Human;
impl Pilot for Human {
fn fly(&self) {
println!("This is your captain speaking.")
}
}
impl Wizad for Human {
fn fly(&self) {
println!("Up!")
}
}
impl Human {
fn fly(&self) {
println!("*waving arms furiously*!")
}
}
fn main() {
let person = Human;
person.fly();
Pilot::fly(&person);
Wizad::fly(&person);
}
现在我们来看一下不同的场景
完全限定语法: <Type as Trait>::function(receiver_if_method, netx_ arg, ..);
可以在任何调用函数或方法的地方使用
允许忽略那些从其它上下文能推导出来的部分
当Rust无法区分你期望调用哪个具体实现的时候,才需使用这种语法
trait Animal {
fn baby_name()-> String;
}
struct Dog;
impl Dog {
fn baby_name()-> String{
String::from("Spot")
}
}
impl Animal for Dog {
fn baby_name()-> String{
String::from("puppy")
}
}
fn main() {
println!("A baby dog is called a {}",Dog::baby_name());
println!("A baby dog is called a {}",<Dog as Animal>::baby_name());
}
使用supertrait来要求trait附带其它trait的功能
需要在一个trait中使用其它trait的功能:
需要被依赖的trait 也被实现
那个被间接依赖的trait 就是当前trait 的supertrait
use std::fmt;
trait OutlinePrint: fmt::Display {
fn OutlinePrint(&self) {
let output = self.to_string();
let len = output.len();
println!("{}","*".repeat(len + 4));
println!("*{}*"," ".repeat(len + 2));
println!("* {} *",output);
println!("*{}*"," ".repeat(len + 2));
println!("{}","*".repeat(len + 4));
}
}
struct Point {
x:i32,
y:i32
}
impl OutlinePrint for Point {
}
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f,"({},{})",self.x,self.y)
}
}
fn main() {
}
使用newtype模式在外部类型上实现外部trait
孤儿规则:只有当trait或类型定义在本地包时,才能为该类型实现这个trait
可以通过newtype模式来绕过这一规则
利用tuplestruct(元组结构体)创建--个新的类型
use std::fmt;
struct Wrapper(Vec<String>);
impl fmt::Display for Wrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f,"[{}]",self.0.join(", "))
}
}
fn main() {
let w = Wrapper(vec![String::from("Hello World")]);
println!("w={}",w);
}