|
|
@ -8,7 +8,7 @@ Go语言在2022年,就要正式引入泛型,被视为在1.0版本后,语
|
|
|
|
fn add_i8(a:i8, b:i8) -> i8 {
|
|
|
|
fn add_i8(a:i8, b:i8) -> i8 {
|
|
|
|
a + b
|
|
|
|
a + b
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn add_i32(a:i16, b:i16) -> i16 {
|
|
|
|
fn add_i32(a:i32, b:i32) -> i32 {
|
|
|
|
a + b
|
|
|
|
a + b
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn add_f64(a:f64, b:f64) -> f64 {
|
|
|
|
fn add_f64(a:f64, b:f64) -> f64 {
|
|
|
@ -17,7 +17,7 @@ fn add_f64(a:f64, b:f64) -> f64 {
|
|
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
fn main() {
|
|
|
|
println!("add i8: {}", add_i8(2i8, 3i8));
|
|
|
|
println!("add i8: {}", add_i8(2i8, 3i8));
|
|
|
|
println!("add i16: {}", add_i32(20, 30));
|
|
|
|
println!("add i32: {}", add_i32(20, 30));
|
|
|
|
println!("add f64: {}", add_f64(1.23, 1.23));
|
|
|
|
println!("add f64: {}", add_f64(1.23, 1.23));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
```
|
|
|
@ -36,7 +36,7 @@ fn add<T>(a:T, b:T) -> T {
|
|
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
fn main() {
|
|
|
|
println!("add i8: {}", add(2i8, 3i8));
|
|
|
|
println!("add i8: {}", add(2i8, 3i8));
|
|
|
|
println!("add i16: {}", add(20, 30));
|
|
|
|
println!("add i32: {}", add(20, 30));
|
|
|
|
println!("add f64: {}", add(1.23, 1.23));
|
|
|
|
println!("add f64: {}", add(1.23, 1.23));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
```
|
|
|
@ -199,10 +199,10 @@ enum Result<T, E> {
|
|
|
|
|
|
|
|
|
|
|
|
该枚举和`Option`一样,主要用于函数返回值,与`Option`用于值的存在与否不同,`Result`关注的主要是正确性。
|
|
|
|
该枚举和`Option`一样,主要用于函数返回值,与`Option`用于值的存在与否不同,`Result`关注的主要是正确性。
|
|
|
|
|
|
|
|
|
|
|
|
如果函数正常运行,则最后返回一个`Ok(T)`,`T`是函数具体的返回值类型,如果函数异常运行,则返回一个`Err(E)`,`E`是具体的错误值。例如打开一个文件:当成功打开文件,返回`Ok(std::fs::File)`,因此`T` 对应的是 `std::fs::File` 类型;而当打开文件时出现问题时,返回`Err(std::io::Error)`, `E`对应的是`std::io::Error`类型。
|
|
|
|
如果函数正常运行,则最后返回一个`Ok(T)`,`T`是函数具体的返回值类型,如果函数异常运行,则返回一个`Err(E)`,`E`是错误类型。例如打开一个文件:当成功打开文件,返回`Ok(std::fs::File)`,因此`T` 对应的是 `std::fs::File` 类型;而当打开文件时出现问题时,返回`Err(std::io::Error)`, `E`对应的是`std::io::Error`类型。
|
|
|
|
|
|
|
|
|
|
|
|
## 方法中使用泛型
|
|
|
|
## 方法中使用泛型
|
|
|
|
上一节中,我们讲到何为方法以及如何在结构体和枚举上定义方法。方法上也可以使用泛型:
|
|
|
|
上一章中,我们讲到何为方法以及如何在结构体和枚举上定义方法。方法上也可以使用泛型:
|
|
|
|
```rust
|
|
|
|
```rust
|
|
|
|
struct Point<T> {
|
|
|
|
struct Point<T> {
|
|
|
|
x: T,
|
|
|
|
x: T,
|
|
|
@ -268,7 +268,7 @@ impl Point<f32> {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## const泛型(Rust最新版本引入的重要特性)
|
|
|
|
## const泛型(Rust 1.51版本引入的重要特性)
|
|
|
|
在之前的泛型中,可以抽象为一句话:针对类型实现的泛型,所有的泛型都是为了抽象不同的类型,那有没有针对值的泛型?可能很多同学感觉很难理解,值怎么使用泛型?不急,我们先从数组讲起。
|
|
|
|
在之前的泛型中,可以抽象为一句话:针对类型实现的泛型,所有的泛型都是为了抽象不同的类型,那有没有针对值的泛型?可能很多同学感觉很难理解,值怎么使用泛型?不急,我们先从数组讲起。
|
|
|
|
|
|
|
|
|
|
|
|
在[数组](../compound-type/array.md)那节,有提到过很重要的一点:`[i32; 2]`和`[i32; 3]`是不同的数组类型,例如以下代码:
|
|
|
|
在[数组](../compound-type/array.md)那节,有提到过很重要的一点:`[i32; 2]`和`[i32; 3]`是不同的数组类型,例如以下代码:
|
|
|
@ -327,7 +327,7 @@ fn main() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
也不难,唯一要注意的是需要对T加一个限制`std::fmt::Debug`,该限制表明`T`可以用在`println!("{:?}", arr)`中,因为`{"?}`形式的格式化输出需要`arr`实现该特征。
|
|
|
|
也不难,唯一要注意的是需要对T加一个限制`std::fmt::Debug`,该限制表明`T`可以用在`println!("{:?}", arr)`中,因为`{:?}`形式的格式化输出需要`arr`实现该特征。
|
|
|
|
|
|
|
|
|
|
|
|
通过引用,我们可以很轻松的解决处理任何类型数组的问题,但是如果在某些场景下不适宜用引用或者干脆不能用呢?那真的没什么好办法了,你们知道为什么以前Rust的一些数组库,在使用的时候都限定长度不超过32吗?因为它们会为每个长度都单独实现一个函数,简直。。。毫无人性。
|
|
|
|
通过引用,我们可以很轻松的解决处理任何类型数组的问题,但是如果在某些场景下不适宜用引用或者干脆不能用呢?那真的没什么好办法了,你们知道为什么以前Rust的一些数组库,在使用的时候都限定长度不超过32吗?因为它们会为每个长度都单独实现一个函数,简直。。。毫无人性。
|
|
|
|
|
|
|
|
|
|
|
@ -356,7 +356,7 @@ fn main() {
|
|
|
|
|
|
|
|
|
|
|
|
## 泛型的性能
|
|
|
|
## 泛型的性能
|
|
|
|
|
|
|
|
|
|
|
|
在Rust中泛型是零消耗的抽象,意味着你在使用泛型时,完全不用担心性能上的问题。
|
|
|
|
在Rust中泛型是零成本的抽象,意味着你在使用泛型时,完全不用担心性能上的问题。
|
|
|
|
|
|
|
|
|
|
|
|
但是任何选择都是权衡得失的,既然我们获得了性能上的巨大优势,那么又失去了什么呢?Rust采用的是在编译期,为泛型对应的多个类型,生成各自的代码,因此损失了编译速度和增大了最终生成文件的大小。
|
|
|
|
但是任何选择都是权衡得失的,既然我们获得了性能上的巨大优势,那么又失去了什么呢?Rust采用的是在编译期,为泛型对应的多个类型,生成各自的代码,因此损失了编译速度和增大了最终生成文件的大小。
|
|
|
|
|
|
|
|
|
|
|
|