泛型(generics)

rust 也有泛型,这种最早出现1970年代的Ada语言中,后来被许多基于对象和面向对象的语言所采用,包括BETA、 C++、java。
rust 也借鉴了这一特性。
这种特性让程序有更好的通用性。

1.简单示例-结构体泛型

给结构体 Point 定义一个泛型 T

1
2
3
4
5
6
7
8
9
struct Point<T> {
x: T,
y: T,
}

fn main() {
let integer = Point { x: 5, y: 10 };
let float = Point { x: 1.0, y: 4.0 };
}

不同类型泛型

1
2
3
4
5
6
7
8
9
10
struct Point<T, U> {
x: T,
y: U,
}

fn main() {
let both_integer = Point { x: 5, y: 10 };
let both_float = Point { x: 1.0, y: 4.0 };
let integer_and_float = Point { x: 5, y: 4.0 };
}

2.函数泛型-同方法泛型

传入什么,就返回什么类型

1
fn largest<T>(list: &[T]) -> T {

那会不会跟java一样,可以类泛型作用到方法。
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 largest<T>(list: &[T]) -> &T {
let mut largest = &list[0];

for item in list {
if item > largest {
largest = item;
}
}

largest
}

fn main() {
let number_list = vec![34, 50, 25, 100, 65];

let result = largest(&number_list);
println!("The largest number is {}", result);

let char_list = vec!['y', 'm', 'a', 'q'];

let result = largest(&char_list);
println!("The largest char is {}", result);
}

3.方法泛型

真有这个。

用法和定义同java一样。
实现一个Point 的方法,类型为T。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct Point<T> {
x: T,
y: T,
}

impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}

fn main() {
let p = Point { x: 5, y: 10 };

println!("p.x = {}", p.x());
}

泛型指定限制(constraint)
这个例子,也是实现Point,但是类型为具体类型 f32

1
2
3
4
5
impl Point<f32> {
fn distance_from_origin(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}

结合 self 使用
注意 x 返回的是 self.x 所以是调用者 p1 自己的x

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct Point<X1, Y1> {
x: X1,
y: Y1,
}

impl<X1, Y1> Point<X1, Y1> {
fn mixup<X2, Y2>(self, other: Point<X2, Y2>) -> Point<X1, Y2> {
Point {
x: self.x,
y: other.y,
}
}
}

fn main() {
let p1 = Point { x: 5, y: 10.4 };
let p2 = Point { x: "Hello", y: 'c' };

let p3 = p1.mixup(p2);

println!("p3.x = {}, p3.y = {}", p3.x, p3.y);
}

结果:

1
p3.x = 5, p3.y = c

泛型代码的性能

Rust 通过在编译时进行泛型代码的 单态化(monomorphization)来保证效率。
单态化是一个通过填充编译时使用的具体类型,将通用代码转换为特定代码的过程。

java也是一样的方式,通过泛型擦除来实现,就是
泛型信息只存在于代码编译阶段,在java的运行期(已经生成字节码文件后)与泛型相关的信息会被擦除掉。
所以其实也是在编译期做文章。

总结

rust 的很多方面,都借鉴了java的总分特性,不是指泛型,而是指后面还明更多的部分,比如迭代器,用起来很丝滑。
还有如golang部份的特性,在channel部分,用起来,就是像golang