泛型(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); }
|
结果:
泛型代码的性能
Rust 通过在编译时进行泛型代码的 单态化(monomorphization)
来保证效率。
单态化是一个通过填充编译时使用的具体类型,将通用代码转换为特定代码的过程。
java也是一样的方式,通过泛型擦除来实现,就是
泛型信息只存在于代码编译阶段,在java的运行期(已经生成字节码文件后)与泛型相关的信息会被擦除掉。
所以其实也是在编译期做文章。
总结
rust 的很多方面,都借鉴了java的总分特性,不是指泛型,而是指后面还明更多的部分,比如迭代器,用起来很丝滑。
还有如golang
部份的特性,在channel
部分,用起来,就是像golang
。