Update advance-trait.md

pull/213/head
Allan Downey 3 years ago
parent 945f8edd9c
commit aa90b48cad

@ -126,7 +126,7 @@ impl Add<Meters> for Millimeters {
} }
``` ```
这里,是进行`Millimeters + Meters`的操作因此此时不能再使用默认的RHS否则就会变成`Millimeters + Millimeters`的形式。使用`Add<Meters>`可以将`RHS`指定为`Meters`,那么`fn add(self, rhs: RHS) `自然而言的变成了`Millimeters`和`Meters`的相加. 这里,是进行 `Millimeters + Meters` 的操作,因此此时不能再使用默认的 `RHS`,否则就会变成 `Millimeters + Millimeters` 的形式。使用 `Add<Meters>` 可以将 `RHS` 指定为 `Meters`,那么 `fn add(self, rhs: RHS)` 自然而言的变成了 `Millimeters``Meters` 的相加。
默认类型参数主要用于两个方面: 默认类型参数主要用于两个方面:
1. 减少实现的样板代码 1. 减少实现的样板代码
@ -136,10 +136,10 @@ impl Add<Meters> for Millimeters {
对于第二点,也很好理解,如果你在一个复杂类型的基础上,新引入一个泛型参数,可能需要修改很多地方,但是如果新引入的泛型参数有了默认类型,情况就会好很多。 对于第二点,也很好理解,如果你在一个复杂类型的基础上,新引入一个泛型参数,可能需要修改很多地方,但是如果新引入的泛型参数有了默认类型,情况就会好很多。
归根到底,默认泛型参数,是有用的,但是大多数情况下,咱们确实用不到,当需要用到时,大家再回头来查阅本章即可,**手上有剑,心中不慌**. 归根到底,默认泛型参数,是有用的,但是大多数情况下,咱们确实用不到,当需要用到时,大家再回头来查阅本章即可,**手上有剑,心中不慌**
## 调用同名的方法 ## 调用同名的方法
不同特征拥有同名的方法是很正常的事情,你没有任何办法阻止这一点,甚至除了特征上的同名方法外,在你的类型上,也有同名方法: 不同特征拥有同名的方法是很正常的事情,你没有任何办法阻止这一点,甚至除了特征上的同名方法外,在你的类型上,也有同名方法
```rust ```rust
trait Pilot { trait Pilot {
fn fly(&self); fn fly(&self);
@ -170,7 +170,7 @@ impl Human {
} }
``` ```
这里,不仅仅两个特征`Pilot`和`Wizard`有`fly`方法,就连实现那两个特征的`Human`元结构体,也拥有一个同名方法`fly`(这世界怎么了,非常这么卷吗?程序员何苦难为程序员,哎)。 这里,不仅仅两个特征 `Pilot``Wizard``fly` 方法,就连实现那两个特征的 `Human` 元结构体,也拥有一个同名方法 `fly` (这世界怎么了,非要这么卷吗?程序员何苦难为程序员,哎)。
既然代码已经不可更改,那下面我们来讲讲该如何调用这些 `fly` 方法。 既然代码已经不可更改,那下面我们来讲讲该如何调用这些 `fly` 方法。
@ -195,14 +195,14 @@ fn main() {
} }
``` ```
运行后依次输出: 运行后依次输出
```console ```console
This is your captain speaking. This is your captain speaking.
Up! Up!
*waving arms furiously* *waving arms furiously*
``` ```
因为`fly`方法的参数是`self`,当显示的调用时,编译器就可以根据调用的类型(`self`的类型)决定具体调用哪个方法。 因为 `fly` 方法的参数是 `self`,当显式调用时,编译器就可以根据调用的类型( `self` 的类型)决定具体调用哪个方法。
这个时候问题又来了,如果方法没有 `self` 参数呢?稍等,估计有读者会问:还有方法没有 `self` 参数?看到这个疑问,作者的眼泪不禁流了下来,大明湖畔的[关联函数](../method.md#关联函数),你还记得嘛? 这个时候问题又来了,如果方法没有 `self` 参数呢?稍等,估计有读者会问:还有方法没有 `self` 参数?看到这个疑问,作者的眼泪不禁流了下来,大明湖畔的[关联函数](../method.md#关联函数),你还记得嘛?
@ -240,7 +240,7 @@ fn main() {
} }
``` ```
铛铛,无情报错了: 铛铛,无情报错了
```rust ```rust
error[E0283]: type annotations needed // 需要类型注释 error[E0283]: type annotations needed // 需要类型注释
--> src/main.rs:20:43 --> src/main.rs:20:43
@ -253,18 +253,18 @@ error[E0283]: type annotations needed // 需要类型注释
因为单纯从 `Animal::baby_name()` 上,编译器无法得到任何有效的信息:你想获取哪个动物宝宝的名称?狗宝宝?猪宝宝?还是熊宝宝? 因为单纯从 `Animal::baby_name()` 上,编译器无法得到任何有效的信息:你想获取哪个动物宝宝的名称?狗宝宝?猪宝宝?还是熊宝宝?
此时,就需要使用**完全限定语法**. 此时,就需要使用**完全限定语法**
##### 完全限定语法 ##### 完全限定语法
完全限定语法是调用函数最为明确的方式: 完全限定语法是调用函数最为明确的方式
```rust ```rust
fn main() { fn main() {
println!("A baby dog is called a {}", <Dog as Animal>::baby_name()); println!("A baby dog is called a {}", <Dog as Animal>::baby_name());
} }
``` ```
在尖括号中,通过`as`关键字我们向Rust编译器提供了类型注解也就是`Animal`就是`Dog`,而不是其他动物,因此最终会调用`impl Animal for Dog `中的方法,获取到其它动物对狗宝宝的称呼:**puppy**. 在尖括号中,通过 `as` 关键字我们向Rust编译器提供了类型注解也就是 `Animal` 就是 `Dog`,而不是其他动物,因此最终会调用 `impl Animal for Dog` 中的方法,获取到其它动物对狗宝宝的称呼:**puppy**
言归正题,完全限定语法定义为: 言归正题,完全限定语法定义为
```rust ```rust
<Type as Trait>::function(receiver_if_method, next_arg, ...); <Type as Trait>::function(receiver_if_method, next_arg, ...);
``` ```
@ -294,7 +294,7 @@ trait OutlinePrint: Display {
等等,这里有一个眼熟的语法: `OutlinePrint: Display`,感觉很像之前讲过的**特征约束**,只不过用在了特征定义中而不是函数的参数中,是的,在某种意义上来说,这和特征约束非常类似,都用来说明一个特征需要实现另一个特征,这里就是:如果你想要实现 `OutlinePrint` 特征,首先你需要实现 `Display` 特征。 等等,这里有一个眼熟的语法: `OutlinePrint: Display`,感觉很像之前讲过的**特征约束**,只不过用在了特征定义中而不是函数的参数中,是的,在某种意义上来说,这和特征约束非常类似,都用来说明一个特征需要实现另一个特征,这里就是:如果你想要实现 `OutlinePrint` 特征,首先你需要实现 `Display` 特征。
想象一下,假如没有这个特征约束,那么`self.to_string`还能够调用吗(`to_string`方法会为实现`Display`特征的类型自动实现)?编译器肯定是不愿意的,会报错说当前作用域中找不到用于`&Self`类型的方法`to_string`: 想象一下,假如没有这个特征约束,那么 `self.to_string` 还能够调用吗( `to_string` 方法会为实现 `Display` 特征的类型自动实现)?编译器肯定是不愿意的,会报错说当前作用域中找不到用于 `&Self` 类型的方法 `to_string`
```rust ```rust
struct Point { struct Point {
x: i32, x: i32,

Loading…
Cancel
Save