一、泛型概念

泛型很多编程语言都会实现的特性。在处理数据结构的时候可以带来很大便利性。或者一些工具函数可以处理多种类型。 当然熟悉go的童鞋,可能要说,没有泛型也可以写数据结构啊。这涉及到反射和泛型的一些差别。泛型在性能上更占优势, 因为大部分语言在实现泛型都会选择特例化类型

1.rust泛型特例化

先给v_str初始化一些&str, 然后push一个int。看编译器报错

1
2
3
4
fn main() {
    let mut v_str = vec!["1123", "345"];
    v_str.push(1);
}

输出

1
2
3
4
5
6
7
8
error[E0308]: mismatched types
 --> src/main.rs:3:16
  |
3 |     v_str.push(1);
  |                ^ expected `&str`, found integer

error: aborting due to previous error

这里的v_str已经是&str类型,再push int就会报错。

所以特例化之后的泛型类型就是具体类型了。泛型不会带来抽象开销,所以效率还是很高的。

2.写法

函数名之后带<T>, 类型使用<T>里面的值。

1
fn foo<T>(t: T){}

二、实战-实现泛型max函数

1.先按感觉写

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
fn max<T>(a: T, b: T) -> T {
    if a < b {
        return b;
    }
    return a;
}

fn main() {
    println!("Hello, world!");
}

2.cargo build 看下输出

从报错上来看,编译器老师傅告诉我们出错原因,和建议。我们先按建议修改下。泛型类型要加下约束,实现了约束的类型可以使用这个max函数。 这个可以理解,编译器加强前置检查。能编译通过后面基本没啥问题。总比某个语言template报错,地球人都看不懂。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
error[E0369]: binary operation `<` cannot be applied to type `T`
 --> src/main.rs:2:10
  |
2 |     if a < b {
  |        - ^ - T
  |        |
  |        T
  |
help: consider restricting type parameter `T`
  |
1 | fn max<T: std::cmp::PartialOrd>(a: T, b: T) -> T {
  |         ^^^^^^^^^^^^^^^^^^^^^^

3.修改之后的代码

运行成功

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
fn max<T: std::cmp::PartialOrd>(a: T, b: T) -> T {
    if a < b {
        return b;
    }
    return a;
}

fn main() {
    println!("{}", max(1, 2));
    println!("{}", max(2.2, 1.1));
    println!("{}", max("hello", "h"));
}

// output:
//       2
//       2.2
//       hello

三、实战-实现泛型index函数

在golang有时候要使用index函数,如果是strings or bytes类型还好,标准库里面有,如果是int 就尴尬了。 也可以用reflect实现,就是速度慢点。当然有泛型的rust这点还是不错的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fn index<T: std::cmp::PartialEq>(a: &[T], b: T) -> i32 {
    for (i, item) in a.iter().enumerate() {
        if item == &b {
            return i as i32;
        }
    }

    return -1;
}

fn main() {
    println!("find index:{}", index(&vec![1, 2, 3, 4, 5,], 5));
    println!("find index:{}", index(&vec![1, 2, 3, 4, 5,], 6));
    println!("find index:{}", index(&vec!["hello", "world"], "world"));
    println!("find index:{}", index(&vec!["hello", "world"], "wo qu"));
}

// output
//       find index:4
//       find index:-1
//       find index:1
//       find index:-1