目录
泛型
fn add<T: std::ops::Add<Output = T>>(a:T, b:T) -> T { a + b } fn main() { println!("add i8: {}", add(2i8, 3i8)); println!("add i32: {}", add(20, 30)); println!("add f64: {}", add(1.23, 1.23)); }
fn largest<T: PartialOrd>(list: &[T]) -> &T { let mut largest = &list[0]; for item in list.iter() { if item > largest { largest = item; } } largest } // or fn largest<T: PartialOrd>(list: &[T]) -> &T { let mut largest_idx = 0_usize; for i in 0..list.len() { if list[i] > list[largest_idx] { largest_idx = i; } } &list[largest_idx] } 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); }
结构体中的泛型
struct Point<T,U> { x: T, y: U, } fn main() { let p = Point{x: 1, y :1.1}; }
枚举中使用泛型
enum Option<T> { Some(T), None, } enum Result<T, E> { Ok(T), Err(E), }
方法中使用泛型
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()); }
需要注意的是,这里的
Point<T>
不再是泛型声明,而是一个完整的结构体类型,因为我们定义的结构体就是Point<T>
而不再是Point
。
除了结构体中的泛型参数,我们还能在该结构体的方法中定义额外的泛型参数,就跟泛型函数一样
struct Point<T, U> { x: T, y: U, } impl<T, U> Point<T, U> { fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> { 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); }
为具体的泛型类型实现方法
impl Point<f32> { fn distance_from_origin(&self) -> f32 { (self.x.powi(2) + self.y.powi(2)).sqrt() } }
const 泛型
const N: usize,表示 const 泛型 N
fn display_array<T: std::fmt::Debug, const N: usize>(arr: [T; N]) { println!("{:?}", arr); } fn main() { let arr: [i32; 3] = [1, 2, 3]; display_array(arr); let arr: [i32; 2] = [1, 2]; display_array(arr); }
const 泛型表达式
// 目前只能在nightly版本下使用 #![allow(incomplete_features)] #![feature(generic_const_exprs)] fn something<T>(val: T) where Assert<{ core::mem::size_of::<T>() < 768 }>: IsTrue, // ^-----------------------------^ 这里是一个 const 表达式,换成其它的 const 表达式也可以 { // } fn main() { something([0u8; 0]); // ok something([0u8; 512]); // ok something([0u8; 1024]); // 编译错误,数组长度是1024字节,超过了768字节的参数长度限制 } // --- pub enum Assert<const CHECK: bool> { // } pub trait IsTrue { // } impl IsTrue for Assert<true> { // }
目前,const 泛型参数只能使用以下形式的实参:
- 一个单独的 const 泛型参数
- 一个字面量 (i.e. 整数, 布尔值或字符).
- 一个具体的 const 表达式( 表达式中不能包含任何 泛型参数)
fn foo<const N: usize>() {} fn bar<T, const M: usize>() { foo::<M>(); // ok: 符合第一种 foo::<2021>(); // ok: 符合第二种 foo::<{20 * 100 + 20 * 10 + 1}>(); // ok: 符合第三种 foo::<{ M + 1 }>(); // error: 违背第三种,const 表达式中不能有泛型参数 M foo::<{ std::mem::size_of::<T>() }>(); // error: 泛型表达式包含了泛型参数 T let _: [u8; M]; // ok: 符合第一种 let _: [u8; std::mem::size_of::<T>()]; // error: 泛型表达式包含了泛型参数 T } fn main() {}
const 泛型还能帮我们避免一些运行时检查,提升性能
pub struct MinSlice<T, const N: usize> { pub head: [T; N], pub tail: [T], } fn main() { let slice: &[u8] = b"Hello, world"; let reference: Option<&u8> = slice.get(6); // 我们知道 `.get` 返回的是 `Some(b' ')` // 但编译器不知道 assert!(reference.is_some()); let slice: &[u8] = b"Hello, world"; // 当编译构建 MinSlice 时会进行长度检查,也就是在编译期我们就知道它的长度是 12 // 在运行期,一旦 `unwrap` 成功,在 `MinSlice` 的作用域内,就再无需任何检查 let minslice = MinSlice::<u8, 12>::from_slice(slice).unwrap(); let value: u8 = minslice.head[6]; assert_eq!(value, b' ') }
<T, const N: usize>
是结构体类型的一部分,和数组类型一样,这意味着长度不同会导致类型不同: Array<i32, 3>
和 Array<i32, 4>
是不同的类型
struct Array<T, const N: usize> { data : [T; N] } fn main() { // 数组里每个元素的类型需要一致 let arrays = [ Array{ data: [1, 2, 3], }, Array { data: [1, 2, 3], }, Array { data: [1, 2, 4] } ]; }
fn print_array<T: std::fmt::Debug, const N: usize>(arr: [T; N]) { println!("{:?}", arr); } fn main() { let arr = [1, 2, 3]; print_array(arr); let arr = ["hello", "world"]; print_array(arr); }
#![allow(incomplete_features)] #![feature(generic_const_exprs)] fn check_size<T>(val: T) where Assert<{ core::mem::size_of::<T>() < 768 }>: IsTrue, { //... } // fix the errors in main fn main() { check_size([0u8; 767]); check_size([0i32; 191]); // &str切片长度为16 check_size(["hello你好"; 47]); // &str is a string reference, containing a pointer and string length in it, so it takes two word long, in x86-64, 1 word = 8 bytes check_size([(); 31].map(|_| "hello你好".to_string())); // String is a smart pointer struct, it has three fields: pointer, length and capacity, each takes 8 bytes // String长度为24 check_size(['中'; 191]); // A char takes 4 bytes in Rust } pub enum Assert<const CHECK: bool> {} pub trait IsTrue {} impl IsTrue for Assert<true> {}