From ae5c686c06df8b97ed69bc2ec8559c20d3bccc17 Mon Sep 17 00:00:00 2001 From: sunface Date: Fri, 10 Dec 2021 23:13:48 +0800 Subject: [PATCH] update --- src/SUMMARY.md | 4 +- src/basic/base-type/function.md | 73 ++++++++- src/basic/compound-type/enum.md | 2 + src/basic/method.md | 263 +++++++++++++++++++++++++++++--- src/img/.DS_Store | Bin 6148 -> 6148 bytes src/img/method-01.png | Bin 0 -> 16486 bytes 6 files changed, 316 insertions(+), 26 deletions(-) create mode 100644 src/img/method-01.png diff --git a/src/SUMMARY.md b/src/SUMMARY.md index e5684c3a..c4bdb0f4 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -35,7 +35,7 @@ - [解构Option](basic/match-pattern/option.md) - [模式适用场景](basic/match-pattern/pattern-match.md) - [全模式列表](basic/match-pattern/all-patterns.md) - - [方法Method(todo)](basic/method.md) + - [方法Method](basic/method.md) - [泛型(todo)](basic/generitic.md) - [特征(todo)](basic/trait.md) - [类型转换 todo](basic/type-converse.md) @@ -163,7 +163,7 @@ - [Benchmark性能测试(todo)](performance/benchmark.md) - [减少Runtime check(todo)](performance/runtime-check.md) - [CPU缓存性能优化](performance/cpu-cache.md) - + - [编译器 todo](compiler/intro.md) - [常见属性标记](compiler/attributes.md) diff --git a/src/basic/base-type/function.md b/src/basic/base-type/function.md index 09212ada..dadb8966 100644 --- a/src/basic/base-type/function.md +++ b/src/basic/base-type/function.md @@ -105,4 +105,75 @@ fn main() { } ``` -`plus_or_substract`函数根据传入`x`的大小来决定是做加法还是减法,若`x > 5`则通过`return`提前返回`x - 5`的值,否则返回`x + 5`的值。 \ No newline at end of file +`plus_or_substract`函数根据传入`x`的大小来决定是做加法还是减法,若`x > 5`则通过`return`提前返回`x - 5`的值,否则返回`x + 5`的值。 + + +#### Rust中的特殊返回类型 + +##### 无返回值`()` + +对于Rust新手来说,有些返回类型很难理解,而且如果你想通过百度或者谷歌去搜索,都不好查询,因为这些符号太常见了,根本难以精确搜索到。 + +例如元类型`()`,是一个零长度的元组。它没啥作用,但是可以用来表达一个函数没有返回值: +- 函数没有返回值,那么返回一个`()` +- 通过`;`结尾的表达式返回一个`()` + + +例如下面的`report`函数会隐式返回一个`()`: +```rust +use std::fmt::Debug; + +fn report(item: T) { + println!("{:?}", item); + +} +``` + +与上面的函数返回值相同,但是下面的函数显式的返回了`()`: + +```rust +fn clear(text: &mut String) -> () { + *text = String::from(""); +} +``` + +在实际编程中,你会经常在错误提示中看到该`()`的身影出没,假如你的函数需要返回一个`u32`值,但是如果你不幸的以`表达式+;`的方式作为函数的最后一行代码,就会报错: +```rust +fn add(x:u32,y:u32) -> u32 { + x + y; +} +``` + +错误如下: +```console +error[E0308]: mismatched types // 类型不匹配 + --> src/main.rs:6:24 + | +6 | fn add(x:u32,y:u32) -> u32 { + | --- ^^^ expected `u32`, found `()` // 期望返回u32,却返回() + | | + | implicitly returns `()` as its body has no tail or `return` expression +7 | x + y; + | - help: consider removing this semicolon +``` + +还记得我们在[语句与表达式](./statement-expression.md)中讲过的吗?只有表达式能返回值,而`;`结尾的是语句,在Rust中,一定要严格区分表达式和语句的区别,这个在其它语言中往往是被忽视的点。 + + +##### 永不返回的函数`!` +感叹号,当用作函数返回值的时候,表示该函数永不返回,特别的,这种语法往往用做会导致程序崩溃的函数: + +```rust +fn dead_end() -> ! { + panic!("你已经到了穷途末路,崩溃吧!"); +} +``` +下面的函数创建了一个无限循环,该循环永不跳出,因此函数也永不返回: + +```rust +fn forever() -> ! { + loop { + //... + }; +} +``` diff --git a/src/basic/compound-type/enum.md b/src/basic/compound-type/enum.md index a0d9e814..5fea9c51 100644 --- a/src/basic/compound-type/enum.md +++ b/src/basic/compound-type/enum.md @@ -163,6 +163,8 @@ struct ChangeColorMessage(i32, i32, i32); // 元组结构体 而且从代码规范角度来看,枚举的实现更简洁,代码内聚性更强,不像结构体的实现,分散在各个地方。 +## 同一化类型 + 最后,再用一个实际项目中的设计考虑,来结束枚举类型的语法学习。 例如我们有一个web服务,需要接受用户的长连接,假设连接有两种:TcpStream和TlsStream,但是我们希望对这两个连接的处理流程相同,也就是用同一个函数来处理这两个连接,代码如下: diff --git a/src/basic/method.md b/src/basic/method.md index e72332c6..955e2b8e 100644 --- a/src/basic/method.md +++ b/src/basic/method.md @@ -1,47 +1,264 @@ -# function-method.md +# 方法Method -## 函数返回 +从面向对象语言过来的同学对于方法肯定不陌生,`class`里面就充斥着方法的概念,在Rust中方法的概念也大差不差,往往和对象成对出现: +```rust +object.method() +``` +例如读取一个文件写入缓冲区,如果用函数的写法`read(f,buffer)`,用方法的写法`f.read(buffer)`. 不过与其它语言`class`跟方法的联动使用不同,Rust的方法往往跟结构体、枚举、特征一起使用,特征将在后面几章进行介绍。 + +## 定义方法 + +Rust使用`impl`来定义方法,例如以下代码: +```rust +struct Circle { + x: f64, + y: f64, + radius: f64, +} + +impl Circle { + // new是Circle的关联函数,因为它的第一个参数不是self + // 这种方法往往用于初始化当前结构体的实例 + fn new(x: f64, y: f64, radius: f64) -> Circle { + Circle { + x: x, + y: y, + radius: radius, + } + } + + // Circle的方法,&self表示借用当前的Circle结构体 + fn area(&self) -> f64 { + std::f64::consts::PI * (self.radius * self.radius) + } +} +``` + +我们这里先不详细展开讲解,首先建立对方法定义的大致印象。下面图片将Rust方法定义与其它语言的方法定义做一下对比: + + + +可以看出,其它语言中所有定义都在`class`中,但是Rust的对象定义和方法定义是分离的,这种数据和使用分离的方式,会给予使用者极高的灵活度。 + +再来看一个例子: +```rust +#[derive(Debug)] +struct Rectangle { + width: u32, + height: u32, +} + +impl Rectangle { + fn area(&self) -> u32 { + self.width * self.height + } +} + +fn main() { + let rect1 = Rectangle { width: 30, height: 50 }; + + println!( + "The area of the rectangle is {} square pixels.", + rect1.area() + ); +} +``` + +该例子定义了一个`Rectangle`结构体,并且在其上定义一个`area`方法,用于计算该矩形的面积。 + +`impl Rectangle {}`表示为`Rectangle`实现方法(`impl` 是实现*implementation* 的缩写),这样的写法标明`impl`语句块中的一切都是跟`Rectangle`相关联的。 + +接下里的内容非常重要,请大家仔细看。在 `area` 的签名中,有一个我们之前没有看到过的关键字`&self`,该关键字指代的是`&Rectangle`类型,换句话说,`self`指代的是`Rectangle`结构体,这样的写法会让我们的代码简洁很多,而且非常便于理解: 我们为哪个结构体实现方法,那么`self`就是指代的该结构体自身。 + +需要注意的是,`self`依然有所有权的概念: +- `self`表示`Rectangle`的所有权转移到该方法中,这种形式用的较少 +- `&self`表示该方法对`Rectangle`的不可变借用 +- `&mut self`表示可变借用 + +总之,`self`的使用就跟函数参数一样,要严格遵守Rust的所有权规则。 + +回到上面的例子中,选择 `&self` 的理由跟在函数中使用 `&Rectangle` 是相同的:我们并不想获取所有权,也无需去改变它,只是希望能够读取结构体中的数据。如果想要在方法中去改变当前的结构体,需要将第一个参数改为 `&mut self`。通过仅仅使用 `self` 作为第一个参数来使方法获取实例的所有权是很少见的,这种使用方式往往用于把当前的对象转成另外一个对象时使用,转换完后,就不再关注之前的对象,且可以防止对之前对象的误调用。 + +简单总结下,使用方法代替函数有以下好处: +- 不用在函数签名中重复书写`self`对应的类型 +- 代码的组织性和内聚性更强,对于代码维护和阅读来说,好处巨大 + +#### 方法名跟结构体字段名相同 +在Rust中,允许方法名跟结构体的字段名相同: +```rust +impl Rectangle { + fn width(&self) -> bool { + self.width > 0 + } +} + +fn main() { + let rect1 = Rectangle { + width: 30, + height: 50, + }; -SPECIAL RETURN TYPES IN RUST + if rect1.width() { + println!("The rectangle has a nonzero width; it is {}", rect1.width); + } +} +``` -If you are new to the language, some return types are difficult to interpret. These are also especially difficult to search for because they are made from symbols rather than words. +当我们使用`rect1.width()`时,Rust知道我们调用的是它的方法,如果使用`rect1.witdh`,则是调用它的字段。 -Known as the unit type, () formally is a zero-length tuple. It is used to express that a function returns no value. Functions that appear to have no return type return (), and expressions that are terminated with a semicolon (;) return (). For example, the report() function in the following code block returns the unit type implicitly: +一般来说,方法跟字段同名,往往适用于实现`getter`访问器,例如: ```rust -use std::fmt::Debug; - -fn report(item: T) { - println!("{:?}", item); - +pub struct Rectangle { + width: u32, + height: u32, +} + +impl Rectangle { + pub fn new(width: u32, height: u32) -> Self { + Rectangle { width, height } + } + pub fn width(&self) -> u32 { + return self.width; + } +} + +fn main() { + let rect1 = Rectangle::new(30, 50); + + println!("{}", rect1.width()); } ``` -And this example returns the unit type explicitly: +用这种方式,我们可以把`Rectangle`的字段设置为私有属性,只需把它的`new`和`witdh`方法设置为公开可见,那么用户就可以创建一个矩形,同时通过访问器`rect1.width()`方法来获取矩形的宽度, 因为`width`字段是私有的,当用户访问`rect1.witdh`字段时,就会报错。 + +> ### `->` 运算符到哪去了? +> +> 在 C/C++ 语言中,有两个不同的运算符来调用方法:`.` 直接在对象上调用方法,而 `->` 在一个对象的指针上调用方法,这时需要先解引用指针。换句话说,如果 `object` 是一个指针,那么 `object->something()`和`(*object).something()`是一样的。 +> +> Rust 并没有一个与 `->` 等效的运算符;相反,Rust 有一个叫 **自动引用和解引用**的功能。方法调用是 Rust 中少数几个拥有这种行为的地方。 +> +> 他是这样工作的:当使用 `object.something()` 调用方法时,Rust 会自动为 `object` 添加 `&`、`&mut` 或 `*` 以便使 `object` 与方法签名匹配。也就是说,这些代码是等价的: +> +> ```rust +> # #[derive(Debug,Copy,Clone)] +> # struct Point { +> # x: f64, +> # y: f64, +> # } +> # +> # impl Point { +> # fn distance(&self, other: &Point) -> f64 { +> # let x_squared = f64::powi(other.x - self.x, 2); +> # let y_squared = f64::powi(other.y - self.y, 2); +> # +> # f64::sqrt(x_squared + y_squared) +> # } +> # } +> # let p1 = Point { x: 0.0, y: 0.0 }; +> # let p2 = Point { x: 5.0, y: 6.5 }; +> p1.distance(&p2); +> (&p1).distance(&p2); +> ``` +> +> 第一行看起来简洁的多。这种自动引用的行为之所以有效,是因为方法有一个明确的接收者———— `self` 的类型。在给出接收者和方法名的前提下,Rust 可以明确地计算出方法是仅仅读取(`&self`),做出修改(`&mut self`)或者是获取所有权(`self`)。事实上,Rust 对方法接收者的隐式借用让所有权在实践中更友好。 +## 带有多个参数的方法 +方法和函数一样,可以使用多个参数: ```rust -fn clear(text: &mut String) -> () { - *text = String::from(""); +impl Rectangle { + fn area(&self) -> u32 { + self.width * self.height + } + + fn can_hold(&self, other: &Rectangle) -> bool { + self.width > other.width && self.height > other.height + } +} + +fn main() { + let rect1 = Rectangle { width: 30, height: 50 }; + let rect2 = Rectangle { width: 10, height: 40 }; + let rect3 = Rectangle { width: 60, height: 45 }; + + println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2)); + println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3)); } ``` -The unit type often occurs in error messages. It’s common to forget that the last expression of a function shouldn’t end with a semicolon. -The exclamation symbol, !, is known as the “Never” type. Never indicates that a function never returns, especially when it is guaranteed to crash. For example, take this code: +## 关联函数 + +现在大家可以思考一个问题,如果为一个结构体定义一个构造器方法?也就是接受几个参数,然后构造并返回该结构体的实例。其实答案在开头的代码片段中就给出了,很简单,不使用`self`中即可。 + +这种定义在`impl`中且没有`self`的函数被称之为**关联函数**: 因为它没有`self`,不能用`f.read()`的形式使用,因此它是一个函数而不是方法,它又在`impl`中,与结构体紧密关联,因此称为关联函数。 + +在之前的代码中,我们已经多次使用过关联函数,例如`String::from`,用于创建一个动态字符串。 ```rust -fn dead_end() -> ! { - panic!("you have reached a dead end"); +# #[derive(Debug)] +# struct Rectangle { +# width: u32, +# height: u32, +# } +# +impl Rectangle { + fn new(w: u32, h: u32) -> Rectangle { + Rectangle { width: w, height: h } + } } ``` -The following example creates an infinite loop that prevents the function from returning: +> Rust中有一个约定俗称的规则,使用`new`来作为构造器的名称,出于设计上的考虑,Rust特地没有用`new`作为关键字 + +因为是函数,所以不能用`.`的方式来调用,我们需要用`::`来调用,例如 `let sq = Rectangle::new(3,3);`。这个方法位于结构体的命名空间中:`::` 语法用于关联函数和模块创建的命名空间。 +## 多个impl定义 +Rust允许我们为一个结构体定义多个`impl`块,目的是提供更多的灵活性和代码组织性,例如当方法多了后,可以把相关的方法组织在同个`impl`块中,那么就可以形成多个`impl`块,各自完成一块儿目标: ```rust -fn forever() -> ! { - loop { - //... - }; +# #[derive(Debug)] +# struct Rectangle { +# width: u32, +# height: u32, +# } +# +impl Rectangle { + fn area(&self) -> u32 { + self.width * self.height + } +} + +impl Rectangle { + fn can_hold(&self, other: &Rectangle) -> bool { + self.width > other.width && self.height > other.height + } +} +``` + +当然,就这个例子而言,我们没必要使用两个`impl`块,这里只是为了演示方便。 + +## 为枚举实现方法 + +枚举类型之所以强大,不仅仅在于它好用、可以[同一化类型](./compound-type/enum.md#同一化类型),还在于,我们可以像结构体一样,为枚举实现方法: + +```rust +#![allow(unused)] +fn main() { +enum Message { + Quit, + Move { x: i32, y: i32 }, + Write(String), + ChangeColor(i32, i32, i32), +} + +impl Message { + fn call(&self) { + // 在这里定义方法体 + } +} + +let m = Message::Write(String::from("hello")); +m.call(); } ``` -As with the unit type, Never sometimes occurs within error messages. The Rust compiler complains about mismatched types when you forget to add a break in your loop block if you’ve indicated that the function returns a non-Never type. \ No newline at end of file +除了结构体和枚举,我们还能为特征(trait)实现方法,将在下下章进行讲解,在此之前,先来看看泛型。 \ No newline at end of file diff --git a/src/img/.DS_Store b/src/img/.DS_Store index 2239cbb7cec4350338643526ad9ac0fe2ecf865c..a307d618b8ed9c41559ae72ef6b60f8ca3d20a60 100644 GIT binary patch delta 157 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