泛型 Generics
泛型是一种参数化多态。
可以编写类型抽象的代码,减少重复代码。
1. 泛型类型 --> 泛型结构体 和 泛型枚举
Box<T>, Option<T>, Result<T, E> 都是泛型类型。
fn main() {
let aa: Box<&str> = Box::new("aadd");
let bb: Option<i32> = Option::Some(67);
let cc: Result<String, &str> = Result::Ok("101aa".to_string());
// unwrap box by *
let mut dd = String::from(*aa);
dd.push_str("ee");
println!("dd = {}", dd);
// unwrap Some<T> by "if let" or unwrap()
if let Some(bb_i1) = bb {
println!("bb_i1 = {}", bb_i1);
}
let bb_i2: i32 = bb.unwrap();
println!("bb.unwrap() = {}", bb.unwrap());
// unwrap Result<T, E> by unwrap()
let ss: String = cc.unwrap();
println!("cc.unwrap() = {}", ss);
}
2. 泛型函数
泛型也可应用于函数,定义泛型函数。
2.1 定义泛型函数:
fn main() {
let a: i32 = foo(1);
let b: &str = foo("hello");
println!("a = {}, b = {}", a, b); // a = 1, b = hello
}
// 泛型函数: 函数方法名称的后面加上 <T>, <A, B>, <A, B, C> 等需要定义的泛型类型
fn foo<T>(x: T) -> T {
return x;
}
2.2 为泛型结构体实现具体方法:
- 与枚举和函数一样,结构体名称后面的 <T> 叫做 泛型声明。
- 泛型只有被声明后才可以被使用。
- Rust中的泛型属于静多态,是一种编译器多态,会被 单态化。
- 单态化意味着,对于上面的foo函数, fn foo<T>(x: T) -> T,编译器要将一个泛型函数生成两个具体类型对应的函数。
#[derive(Debug, PartialEq, Eq)]
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn new(a: T, b: T) -> Self {
Point { x: a, y: b }
}
}
fn main() {
let p1: Point<i32> = Point::new(1, 2);
let p2: Point<&str> = Point::new("1", "2");
assert_eq!(p1, Point { x: 1, y: 2 });
assert_eq!(p2, Point { x: "1", y: "2" });
}
- 单态化静态分发的 好处 是性能好,没有运行时开销。
- 单态化静态分发的 坏处 是容易造成编译后生成的二进制文件膨胀。
2.3 泛型返回值自动推导
编译器还可以对返回值进行自动推导。
#[derive(Debug)]
struct Sa(i32);
#[derive(Debug)]
struct Sd(i32, i32);
trait Inst {
fn new(i: i32) -> Self;
}
impl Inst for Sa {
fn new(i: i32) -> Self {
Sa(i)
}
}
impl Inst for Sd {
fn new(i: i32) -> Self {
Sd(i, i + 10)
}
}
fn try_new<T: Inst>(i: i32) -> T {
T::new(i)
}
fn main() {
let aa: Sa = try_new(1); // 根据声明的变量aa的类型Sa,推导出:需要调用返回值类型为 Sa 的 try_new 函数
let dd: Sd = try_new(2);
println!("aa = {:?}", aa);
println!("dd = {:?}", dd);
}