Trait in Rust

Rust中的Trait非常优美,类似于泛型编程概念。有时候造轮子的时候发现不同的类型具有相同的方法,如果一个个写方法显得不那么友好,比如

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
fn double_i32(x: i32) -> i32 {
    x * 2
}

fn double_i64(x: i64) -> i64 {
    x * 2
}

fn main() {
    println!("double 5_i32 == {}", double_i32(5_i32));
    println!("double 5_i64 == {}", double_i64(5_i64));
}

可以发现非常冗余,那么如何解决这种问题?可以使用Trait,先看Trait的定义

1
2
3
trait Double {
    fn double(&self) -> Self;
}

**首先是trait这个关键字,然后是大写的Double是一种类型,接下来是方法的定义,传入是一个自身的值,传出是一个类型。**来实现这个方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
impl Double for i32 {
    fn double(&self) -> Self {
        self * 2
    }
}

impl Double for i64 {
    fn double(&self) -> Self {
        self * 2
    }
}

可以看到,分别为每一个类型进行实现方法即可。

需求: 如果需要一个quadruple方法,

1
2
3
fn quadruple(x: i32) -> i32 {
    x.double().double()
}

如果仅仅是对i32进行操作,是没有问题的,但是当对i64进行操作,就出现了问题,如果使用泛型

1
2
3
fn quadruple<T>(x:T) -> T {
    x.double().double()
}

也会有问题,出现no method named `double` found for type `T` in the current scope 因此需要对T进行类型标记

1
2
3
fn quadruple<T: Double>(x:T) -> T {
    x.double().double()
}

这样就不会用任何问题了。

  • Inside the definition of the quadruple function, we’re allowed to assume that T has a double method
  • When calling the quadruple function, we have a responsibility to make sure the type we’re using has an implementation of Double

如果一个变量有多种类型,那么可以按照下面的说法

1
2
3
4
5
6
7
8
fn info<T>(x: T)
where
    T: Double + std::fmt::Display + Copy,
{
    println!("Original number: {}", x);
    println!("Doubled number: {}", x.double());
    println!("Quadrupled number: {}", x.double().double());
}

Iter原则

  1. On a normal Vec, we get an iterator that moves the Vec and iterates over the actual values. into_iter
  2. On a reference to a Vec, we borrow the Vec and iterate over references to the values inside it. iter
  3. On a mutable reference, we mutably borrow the Vec and iterate over mutable references to the values inside it. iter_mut

Generic Iterator Functions

1
2
3
4
5
fn print_them_all<I: Iterator<Item = i32>>(iter: I) {
    for x in iter {
        println!("{}", x);
    }
}

参考