|
|
@ -100,7 +100,7 @@ help: consider restricting type parameter `T` // 考虑对T进行类型上的限
|
|
|
|
|
|
|
|
|
|
|
|
还记得我们一开始的 `add` 泛型函数吗?如果你运行它,会得到以下的报错:
|
|
|
|
还记得我们一开始的 `add` 泛型函数吗?如果你运行它,会得到以下的报错:
|
|
|
|
```console
|
|
|
|
```console
|
|
|
|
error[E0369]: cannot add `T` to `T` // 无法将`T`类型跟`T`类型进行相加
|
|
|
|
error[E0369]: cannot add `T` to `T` // 无法将 `T` 类型跟 `T` 类型进行相加
|
|
|
|
--> src/main.rs:2:7
|
|
|
|
--> src/main.rs:2:7
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 | a + b
|
|
|
|
2 | a + b
|
|
|
@ -114,7 +114,7 @@ help: consider restricting type parameter `T`
|
|
|
|
| +++++++++++++++++++++++++++
|
|
|
|
| +++++++++++++++++++++++++++
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
同样的,不是所有`T`类型都能进行相加操作,因此我们需要用`std::ops::Add<Output = T>`对T进行限制:
|
|
|
|
同样的,不是所有 `T` 类型都能进行相加操作,因此我们需要用 `std::ops::Add<Output = T>` 对 `T` 进行限制:
|
|
|
|
```rust
|
|
|
|
```rust
|
|
|
|
fn add<T: std::ops::Add<Output = T>>(a:T, b:T) -> T {
|
|
|
|
fn add<T: std::ops::Add<Output = T>>(a:T, b:T) -> T {
|
|
|
|
a + b
|
|
|
|
a + b
|
|
|
@ -123,7 +123,7 @@ fn add<T: std::ops::Add<Output = T>>(a:T, b:T) -> T {
|
|
|
|
进行如上修改后,就可以正常运行。
|
|
|
|
进行如上修改后,就可以正常运行。
|
|
|
|
|
|
|
|
|
|
|
|
## 结构体中使用泛型
|
|
|
|
## 结构体中使用泛型
|
|
|
|
结构体中的字段类型也可以用泛型来定义,下面代码定义了一个坐标点`Point`,它可以存放任何类型的坐标值:
|
|
|
|
结构体中的字段类型也可以用泛型来定义,下面代码定义了一个坐标点 `Point`,它可以存放任何类型的坐标值:
|
|
|
|
```rust
|
|
|
|
```rust
|
|
|
|
struct Point<T> {
|
|
|
|
struct Point<T> {
|
|
|
|
x: T,
|
|
|
|
x: T,
|
|
|
@ -137,7 +137,7 @@ fn main() {
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
这里有两点需要特别的注意:
|
|
|
|
这里有两点需要特别的注意:
|
|
|
|
- **提前声明**,跟泛型函数定义类似,首先我们在使用泛型参数之前必需要进行声明`Point<T>`,接着就可以在结构体的字段类型中使用`T`来替代具体的类型
|
|
|
|
- **提前声明**,跟泛型函数定义类似,首先我们在使用泛型参数之前必需要进行声明 `Point<T>`,接着就可以在结构体的字段类型中使用 `T` 来替代具体的类型
|
|
|
|
- **x和y是相同的类型**
|
|
|
|
- **x和y是相同的类型**
|
|
|
|
|
|
|
|
|
|
|
|
第二点非常重要,如果使用不同的类型,那么它会导致下面代码的报错:
|
|
|
|
第二点非常重要,如果使用不同的类型,那么它会导致下面代码的报错:
|
|
|
@ -187,7 +187,7 @@ enum Option<T> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`Option<T>` 是一个拥有泛型 `T`,它第一个成员是 `Some(T)`,存放了一个类型为`T`的值。得益于泛型的引入,我们可以在任何一个需要返回值的函数中,去使用 `Option<T>` 枚举类型来做为返回值,用于返回一个任意类型的值 `Some(T)`,或者没有值 `None`。
|
|
|
|
`Option<T>` 是一个拥有泛型 `T` 的枚举类型,它第一个成员是 `Some(T)`,存放了一个类型为 `T` 的值。得益于泛型的引入,我们可以在任何一个需要返回值的函数中,去使用 `Option<T>` 枚举类型来做为返回值,用于返回一个任意类型的值 `Some(T)`,或者没有值 `None`。
|
|
|
|
|
|
|
|
|
|
|
|
对于枚举而言,卧龙凤雏永远是绕不过去的存在:如果是 `Option` 是卧龙,那么 `Result` 就一定是凤雏,得两者可得天下:
|
|
|
|
对于枚举而言,卧龙凤雏永远是绕不过去的存在:如果是 `Option` 是卧龙,那么 `Result` 就一定是凤雏,得两者可得天下:
|
|
|
|
```rust
|
|
|
|
```rust
|
|
|
@ -199,7 +199,7 @@ 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` 类型。
|
|
|
|
|
|
|
|
|
|
|
|
## 方法中使用泛型
|
|
|
|
## 方法中使用泛型
|
|
|
|
上一章中,我们讲到什么是方法以及如何在结构体和枚举上定义方法。方法上也可以使用泛型:
|
|
|
|
上一章中,我们讲到什么是方法以及如何在结构体和枚举上定义方法。方法上也可以使用泛型:
|
|
|
@ -264,7 +264,7 @@ impl Point<f32> {
|
|
|
|
```
|
|
|
|
```
|
|
|
|
这段代码意味着 `Point<f32>` 类型会有一个方法 `distance_from_origin`,而其他 `T` 不是 `f32` 类型的 `Point<T> `实例则没有定义此方法。这个方法计算点实例与坐标`(0.0, 0.0)` 之间的距离,并使用了只能用于浮点型的数学运算符。
|
|
|
|
这段代码意味着 `Point<f32>` 类型会有一个方法 `distance_from_origin`,而其他 `T` 不是 `f32` 类型的 `Point<T> `实例则没有定义此方法。这个方法计算点实例与坐标`(0.0, 0.0)` 之间的距离,并使用了只能用于浮点型的数学运算符。
|
|
|
|
|
|
|
|
|
|
|
|
这样我们就能针对特定的泛型类型实现某个特定的方法,对于其它泛型类型,该方法则并无定义。
|
|
|
|
这样我们就能针对特定的泛型类型实现某个特定的方法,对于其它泛型类型则没有定义该方法。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -369,7 +369,7 @@ where
|
|
|
|
fn main() {
|
|
|
|
fn main() {
|
|
|
|
something([0u8; 0]); // ok
|
|
|
|
something([0u8; 0]); // ok
|
|
|
|
something([0u8; 512]); // ok
|
|
|
|
something([0u8; 512]); // ok
|
|
|
|
something([0u8; 1024]); // 编译错误,数组长度是1024自己,超过了768字节的参数长度限制
|
|
|
|
something([0u8; 1024]); // 编译错误,数组长度是1024字节,超过了768字节的参数长度限制
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ---
|
|
|
|
// ---
|
|
|
|