From b5216178fd450dc069665cfa04d33da71e4999dc Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 1 Jan 2022 12:43:55 +0800 Subject: [PATCH 01/13] update: translate variables --- exercise/exercises/variables/README.md | 10 ++-- exercise/exercises/variables/variables1.rs | 2 +- exercise/exercises/variables/variables2.rs | 7 +-- exercise/exercises/variables/variables3.rs | 6 +-- exercise/exercises/variables/variables4.rs | 2 +- exercise/exercises/variables/variables5.rs | 6 +-- exercise/exercises/variables/variables6.rs | 2 +- exercise/info.toml | 53 ++++++++++------------ 8 files changed, 42 insertions(+), 46 deletions(-) diff --git a/exercise/exercises/variables/README.md b/exercise/exercises/variables/README.md index 11a7a78a..9a47a74d 100644 --- a/exercise/exercises/variables/README.md +++ b/exercise/exercises/variables/README.md @@ -1,9 +1,9 @@ -# Variables +# 变量(Variables) -In Rust, variables are immutable by default. -When a variable is immutable, once a value is bound to a name, you can’t change that value. -You can make them mutable by adding mut in front of the variable name. +在 Rust,变量默认是不可变的. +不可变意味着当一个值被绑定到某个名字上,你就不能再对这个值做出更改。 +当然,你可以通过在变量名前添加 mut 来使它们变得可变。 -## Further information +## 更多信息 - [Variables and Mutability](https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html) diff --git a/exercise/exercises/variables/variables1.rs b/exercise/exercises/variables/variables1.rs index fb391d22..5c352d04 100644 --- a/exercise/exercises/variables/variables1.rs +++ b/exercise/exercises/variables/variables1.rs @@ -12,5 +12,5 @@ /// 加油 💪 fn main() { x = 5; - println!("x has the value {}", x); + println!("x has the value {}", x);// 译:x 的值是 } diff --git a/exercise/exercises/variables/variables2.rs b/exercise/exercises/variables/variables2.rs index 7774a8fb..c08e12ec 100644 --- a/exercise/exercises/variables/variables2.rs +++ b/exercise/exercises/variables/variables2.rs @@ -1,13 +1,14 @@ // variables2.rs -// Make me compile! Execute the command `rustlings hint variables2` if you want a hint :) +// 让我能够编译!执行 `rustex hint variables2` 获取提示 :) // I AM NOT DONE +/// 翻译: [mg-chao](https://github.com/mg-chao) fn main() { let x; if x == 10 { - println!("Ten!"); + println!("Ten!");// 译:十! } else { - println!("Not ten!"); + println!("Not ten!");// 译:不是十! } } diff --git a/exercise/exercises/variables/variables3.rs b/exercise/exercises/variables/variables3.rs index 30ec48ff..cf69ebd2 100644 --- a/exercise/exercises/variables/variables3.rs +++ b/exercise/exercises/variables/variables3.rs @@ -1,11 +1,11 @@ // variables3.rs -// Make me compile! Execute the command `rustlings hint variables3` if you want a hint :) +// 让我能够编译!执行 `rustex hint variables3` 获取提示 :) // I AM NOT DONE fn main() { let x = 3; - println!("Number {}", x); - x = 5; // don't change this line + println!("Number {}", x);// 译:"数字 {}" + x = 5; // don't change this line(译:不要更改这一行) println!("Number {}", x); } diff --git a/exercise/exercises/variables/variables4.rs b/exercise/exercises/variables/variables4.rs index 77f1e9ab..80339890 100644 --- a/exercise/exercises/variables/variables4.rs +++ b/exercise/exercises/variables/variables4.rs @@ -1,5 +1,5 @@ // variables4.rs -// Make me compile! Execute the command `rustlings hint variables4` if you want a hint :) +// 让我能够编译!执行 `rustex hint variables4` 获取提示 :) // I AM NOT DONE diff --git a/exercise/exercises/variables/variables5.rs b/exercise/exercises/variables/variables5.rs index 175eebb3..09ecf810 100644 --- a/exercise/exercises/variables/variables5.rs +++ b/exercise/exercises/variables/variables5.rs @@ -1,11 +1,11 @@ // variables5.rs -// Make me compile! Execute the command `rustlings hint variables5` if you want a hint :) +// 让我能够编译!执行 `rustex hint variables5` 获取提示 :) // I AM NOT DONE fn main() { let number = "T-H-R-E-E"; // don't change this line - println!("Spell a Number : {}", number); + println!("Spell a Number : {}", number);// 译:"拼接的数字:{}" number = 3; - println!("Number plus two is : {}", number + 2); + println!("Number plus two is : {}", number + 2);// 译:"数字加上二是:{}" } diff --git a/exercise/exercises/variables/variables6.rs b/exercise/exercises/variables/variables6.rs index 98666914..2d83d656 100644 --- a/exercise/exercises/variables/variables6.rs +++ b/exercise/exercises/variables/variables6.rs @@ -1,5 +1,5 @@ // variables6.rs -// Make me compile! Execute the command `rustlings hint variables6` if you want a hint :) +// 让我能够编译!执行 `rustex hint variables6` 获取提示 :) // I AM NOT DONE diff --git a/exercise/info.toml b/exercise/info.toml index 38e271e8..22ce26b3 100644 --- a/exercise/info.toml +++ b/exercise/info.toml @@ -13,62 +13,57 @@ name = "variables2" path = "exercises/variables/variables2.rs" mode = "compile" hint = """ -The compiler message is saying that Rust cannot infer the type that the -variable binding `x` has with what is given here. -What happens if you annotate line 7 with a type annotation? -What if you give x a value? -What if you do both? -What type should x be, anyway? -What if x is the same type as 10? What if it's a different type?""" +编译器在说,Rust 无法根据给定内容推断出变量 `x` 的类型. +如果你对第 7 行注明类型,会发生什么? +如果你对 x 赋予一个值呢? +如果你同时做到了以上两点呢? + x 到底是什么类型? +如果 x 与 10 是同一类型,亦或者它是不同的类型呢?""" [[exercises]] name = "variables3" path = "exercises/variables/variables3.rs" mode = "compile" hint = """ -In Rust, variable bindings are immutable by default. But here we're trying -to reassign a different value to x! There's a keyword we can use to make -a variable binding mutable instead.""" +在 Rust,变量绑定默认是不可变的。但我们正试图重新分配 +一个不同的值给 x !我们可以使用一个关键字使变量可变。""" [[exercises]] name = "variables4" path = "exercises/variables/variables4.rs" mode = "compile" hint = """ -Oops! In this exercise, we have a variable binding that we've created on -line 7, and we're trying to use it on line 8, but we haven't given it a -value. We can't print out something that isn't there; try giving x a value! -This is an error that can cause bugs that's very easy to make in any -programming language -- thankfully the Rust compiler has caught this for us!""" +糟了!在这个练习中,我们在第 7 行创建了一个变量,然后试图在第 8 行 +使用它,但是它并没被赋值!我们无法打印出不存在的内容,所以尝试赋予 x 一个值! +这个错误造成的 Bug 在任何编程语言中都非常容易发生——感谢 Rust 编译器提醒了我们""" [[exercises]] name = "variables5" path = "exercises/variables/variables5.rs" mode = "compile" hint = """ -In variables3 we already learned how to make an immutable variable mutable -using a special keyword. Unfortunately this doesn't help us much in this exercise -because we want to assign a different typed value to an existing variable. Sometimes -you may also like to reuse existing variable names because you are just converting -values to different types like in this exercise. -Fortunately Rust has a powerful solution to this problem: 'Shadowing'! -You can read more about 'Shadowing' in the book's section 'Variables and Mutability': +在 variables3 中,我们已经学会了使用一个特殊的关键字使一个不可变的变量变得可变。 +可惜的是,在这个练习中,这个方法并不管用,因为我们想给一个现有的变量分配一个不 +同类型的值。有时,你会想重复使用现有的变量名称,因为你只是将数值转换为不同的类型,就像 +本练习中一样。幸运的是,Rust 有一个强大的技术可以解决这个问题:变量遮蔽(Shadowing)! +有关变量遮蔽的更多内容可通过这本书的 'Variables and Mutability'* 章节了解: https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#shadowing -Try to solve this exercise afterwards using this technique.""" +尝试使用此技术解决此练习。 + +译:Variables and Mutability:变量与可变性""" [[exercises]] name = "variables6" path = "exercises/variables/variables6.rs" mode = "compile" hint = """ -We know about variables and mutability, but there is another important type of -variable available; constants. -Constants are always immutable and they are declared with keyword 'const' rather -than keyword 'let'. -Constants types must also always be annotated. +我们已经了解了变量与可变性,但还有另一种重要的变量类型;常量(Constant)。 +常量永远不可改变的,它用关键字 'const' 而非关键字 'let' 声明,并且其类型也必须被注明。 -Read more about constants under 'Differences Between Variables and Constants' in the book's section 'Variables and Mutability': +更多关于常量的信息 'Differences Between Variables and Constants'* 在这本书的章节 'Variables and Mutability': https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants + +译:Differences Between Variables and Constants:变量与常量的区别 """ # FUNCTIONS From 91f9f6ea1af7e6793fba482a50d35c4fb2f357e0 Mon Sep 17 00:00:00 2001 From: l1ch40 Date: Sat, 1 Jan 2022 17:03:09 +0800 Subject: [PATCH 02/13] =?UTF-8?q?fix:=20=E4=BF=AE=E6=AD=A3=E5=86=85?= =?UTF-8?q?=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- course-book/contents/basic/base-type/numbers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/course-book/contents/basic/base-type/numbers.md b/course-book/contents/basic/base-type/numbers.md index 2882a34b..4b0d9734 100644 --- a/course-book/contents/basic/base-type/numbers.md +++ b/course-book/contents/basic/base-type/numbers.md @@ -285,7 +285,7 @@ use num::complex::Complex; - **Rust拥有相当多的数值类型**. 因此你需要熟悉这些类型所占用的字节数,这样就知道该类型允许的大小范围以及你选择的类型是否能表达负数 - **类型转换必须是显式的**. Rust永远也不会偷偷把你的16bit整数转换成32bit整数 -- **Rust的数值上可以使用方法**. 例如你可以用以下方法来将`24.5`取整: `13.14_f32.round()`, 在这里我们使用了类型后缀,因为编译器需要知道`13.14`的具体类型 +- **Rust的数值上可以使用方法**. 例如你可以用以下方法来将`13.14`取整: `13.14_f32.round()`, 在这里我们使用了类型后缀,因为编译器需要知道`13.14`的具体类型 数值类型的讲解已经基本结束,接下来来看看字符和布尔类型。 From 4178bd9a8dce7d1ffb20ead72babf02f11cd5583 Mon Sep 17 00:00:00 2001 From: "Mr.zhang" Date: Sat, 1 Jan 2022 23:06:28 +0800 Subject: [PATCH 03/13] Update match-if-let.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复代码缺失和错别字 --- course-book/contents/basic/match-pattern/match-if-let.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/course-book/contents/basic/match-pattern/match-if-let.md b/course-book/contents/basic/match-pattern/match-if-let.md index bcfb9fc6..4ca5b69d 100644 --- a/course-book/contents/basic/match-pattern/match-if-let.md +++ b/course-book/contents/basic/match-pattern/match-if-let.md @@ -277,7 +277,7 @@ enum MyEnum { } fn main() { - let v = vec![MyEnum::Foo,MyEnum::Bar,MyEnum::F + let v = vec![MyEnum::Foo,MyEnum::Bar,MyEnum::Foo]; } ``` @@ -286,7 +286,7 @@ fn main() { v.iter().filter(|x| x == MyEnum:::Foo); ``` -但是,实际上这行代码会保存,因为你无法将`x`跟一个类型进行比较。好在,你可以使用`match`来完成,但是会导致代码更为啰嗦,是否有更简洁的方式?答案是使用`matches!`: +但是,实际上这行代码会报错,因为你无法将`x`跟一个类型进行比较。好在,你可以使用`match`来完成,但是会导致代码更为啰嗦,是否有更简洁的方式?答案是使用`matches!`: ```rust v.iter().filter(|x| matches!(x, MyEnum::Foo)); ``` @@ -336,4 +336,4 @@ fn main() { } ``` -需要注意的是,**`match`中的变量覆盖其实不是那么的容易看出**,因此要小心! \ No newline at end of file +需要注意的是,**`match`中的变量覆盖其实不是那么的容易看出**,因此要小心! From 4bd54d382a926be4813e29f6d18fa1de2a1e0784 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 2 Jan 2022 10:23:22 +0800 Subject: [PATCH 04/13] fix --- exercise/exercises/functions/README.md | 6 +++--- exercise/exercises/variables/variables3.rs | 1 + exercise/exercises/variables/variables4.rs | 1 + exercise/exercises/variables/variables5.rs | 1 + exercise/exercises/variables/variables6.rs | 1 + 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/exercise/exercises/functions/README.md b/exercise/exercises/functions/README.md index 66547bd4..58465d40 100644 --- a/exercise/exercises/functions/README.md +++ b/exercise/exercises/functions/README.md @@ -1,7 +1,7 @@ -# Functions +# 函数(Functions) -Here, you'll learn how to write functions and how Rust's compiler can trace things way back. +在这里,你将学习如何编写函数,以及 Rust 的编译器如何对事物进行追溯(way back)。 -## Further information +## 更多信息 - [How Functions Work](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html) diff --git a/exercise/exercises/variables/variables3.rs b/exercise/exercises/variables/variables3.rs index cf69ebd2..00ebcbe9 100644 --- a/exercise/exercises/variables/variables3.rs +++ b/exercise/exercises/variables/variables3.rs @@ -3,6 +3,7 @@ // I AM NOT DONE +/// 翻译: [mg-chao](https://github.com/mg-chao) fn main() { let x = 3; println!("Number {}", x);// 译:"数字 {}" diff --git a/exercise/exercises/variables/variables4.rs b/exercise/exercises/variables/variables4.rs index 80339890..cdaf970d 100644 --- a/exercise/exercises/variables/variables4.rs +++ b/exercise/exercises/variables/variables4.rs @@ -3,6 +3,7 @@ // I AM NOT DONE +/// 翻译: [mg-chao](https://github.com/mg-chao) fn main() { let x: i32; println!("Number {}", x); diff --git a/exercise/exercises/variables/variables5.rs b/exercise/exercises/variables/variables5.rs index 09ecf810..87a0d628 100644 --- a/exercise/exercises/variables/variables5.rs +++ b/exercise/exercises/variables/variables5.rs @@ -3,6 +3,7 @@ // I AM NOT DONE +/// 翻译: [mg-chao](https://github.com/mg-chao) fn main() { let number = "T-H-R-E-E"; // don't change this line println!("Spell a Number : {}", number);// 译:"拼接的数字:{}" diff --git a/exercise/exercises/variables/variables6.rs b/exercise/exercises/variables/variables6.rs index 2d83d656..b10eafd9 100644 --- a/exercise/exercises/variables/variables6.rs +++ b/exercise/exercises/variables/variables6.rs @@ -3,6 +3,7 @@ // I AM NOT DONE +/// 翻译: [mg-chao](https://github.com/mg-chao) const NUMBER = 3; fn main() { println!("Number {}", NUMBER); From 6dc27e4c7b40cc23b6c22c4ada4a6e57c080cad8 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 2 Jan 2022 10:25:26 +0800 Subject: [PATCH 05/13] fix --- exercise/exercises/functions/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/exercise/exercises/functions/README.md b/exercise/exercises/functions/README.md index 58465d40..66547bd4 100644 --- a/exercise/exercises/functions/README.md +++ b/exercise/exercises/functions/README.md @@ -1,7 +1,7 @@ -# 函数(Functions) +# Functions -在这里,你将学习如何编写函数,以及 Rust 的编译器如何对事物进行追溯(way back)。 +Here, you'll learn how to write functions and how Rust's compiler can trace things way back. -## 更多信息 +## Further information - [How Functions Work](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html) From 870c198982f33e42e8238288aaa8d4557a3e5fdd Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 2 Jan 2022 10:40:59 +0800 Subject: [PATCH 06/13] save --- exercise/exercises/functions/README.md | 6 +++--- exercise/exercises/functions/functions1.rs | 3 ++- exercise/exercises/functions/functions2.rs | 3 ++- exercise/info.toml | 10 ++++------ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/exercise/exercises/functions/README.md b/exercise/exercises/functions/README.md index 66547bd4..8e7cf63c 100644 --- a/exercise/exercises/functions/README.md +++ b/exercise/exercises/functions/README.md @@ -1,7 +1,7 @@ -# Functions +# 函数(Functions) -Here, you'll learn how to write functions and how Rust's compiler can trace things way back. +在本练习,你将学习如何编写一个函数,以及 Rust 的编译器怎样对事物进行追溯(way back)。 -## Further information +## 更多信息 - [How Functions Work](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html) diff --git a/exercise/exercises/functions/functions1.rs b/exercise/exercises/functions/functions1.rs index 31125278..f18825d9 100644 --- a/exercise/exercises/functions/functions1.rs +++ b/exercise/exercises/functions/functions1.rs @@ -1,8 +1,9 @@ // functions1.rs -// Make me compile! Execute `rustlings hint functions1` for hints :) +// 让我能够编译!执行 `rustex hint functions1` 获取提示 :) // I AM NOT DONE +/// 翻译: [mg-chao](https://github.com/mg-chao) fn main() { call_me(); } diff --git a/exercise/exercises/functions/functions2.rs b/exercise/exercises/functions/functions2.rs index 5721a172..915ebec1 100644 --- a/exercise/exercises/functions/functions2.rs +++ b/exercise/exercises/functions/functions2.rs @@ -1,8 +1,9 @@ // functions2.rs -// Make me compile! Execute `rustlings hint functions2` for hints :) +// 让我能够编译!执行 `rustex hint functions2` 获取提示 :) // I AM NOT DONE +/// 翻译: [mg-chao](https://github.com/mg-chao) fn main() { call_me(3); } diff --git a/exercise/info.toml b/exercise/info.toml index 38e271e8..dca534de 100644 --- a/exercise/info.toml +++ b/exercise/info.toml @@ -78,18 +78,16 @@ name = "functions1" path = "exercises/functions/functions1.rs" mode = "compile" hint = """ -This main function is calling a function that it expects to exist, but the -function doesn't exist. It expects this function to have the name `call_me`. -It expects this function to not take any arguments and not return a value. -Sounds a lot like `main`, doesn't it?""" +主函数中正试图调用一个名为 `call_me` 的函数,可这个函数并不存在。 +它希望这个函数不接受任何参数,同时也不返回值。 +听起来很像 `main` 函数,不是吗?""" [[exercises]] name = "functions2" path = "exercises/functions/functions2.rs" mode = "compile" hint = """ -Rust requires that all parts of a function's signature have type annotations, -but `call_me` is missing the type annotation of `num`.""" + Rust 要求函数签名有类型标注,但是 `call_me` 函数缺少 `num` 的类型注明。""" [[exercises]] name = "functions3" From a5e17d7544cf76841507cc58b6e4c2552dde98a0 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 2 Jan 2022 10:42:45 +0800 Subject: [PATCH 07/13] fix --- exercise/info.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercise/info.toml b/exercise/info.toml index 22ce26b3..9c460c91 100644 --- a/exercise/info.toml +++ b/exercise/info.toml @@ -14,7 +14,7 @@ path = "exercises/variables/variables2.rs" mode = "compile" hint = """ 编译器在说,Rust 无法根据给定内容推断出变量 `x` 的类型. -如果你对第 7 行注明类型,会发生什么? +如果你对第 7 行标注类型,会发生什么? 如果你对 x 赋予一个值呢? 如果你同时做到了以上两点呢? x 到底是什么类型? @@ -58,7 +58,7 @@ path = "exercises/variables/variables6.rs" mode = "compile" hint = """ 我们已经了解了变量与可变性,但还有另一种重要的变量类型;常量(Constant)。 -常量永远不可改变的,它用关键字 'const' 而非关键字 'let' 声明,并且其类型也必须被注明。 +常量永远不可改变的,它用关键字 'const' 而非关键字 'let' 声明,并且其类型也必须被标注。 更多关于常量的信息 'Differences Between Variables and Constants'* 在这本书的章节 'Variables and Mutability': https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants From e00febf87650fef10353617695d9dde0a582a6c9 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 2 Jan 2022 11:12:07 +0800 Subject: [PATCH 08/13] update --- exercise/exercises/functions/functions2.rs | 2 +- exercise/exercises/functions/functions3.rs | 3 ++- exercise/exercises/functions/functions4.rs | 9 ++++---- exercise/exercises/functions/functions5.rs | 5 +++-- exercise/info.toml | 24 ++++++++++------------ 5 files changed, 22 insertions(+), 21 deletions(-) diff --git a/exercise/exercises/functions/functions2.rs b/exercise/exercises/functions/functions2.rs index 915ebec1..ff5b907a 100644 --- a/exercise/exercises/functions/functions2.rs +++ b/exercise/exercises/functions/functions2.rs @@ -10,6 +10,6 @@ fn main() { fn call_me(num:) { for i in 0..num { - println!("Ring! Call number {}", i + 1); + println!("Ring! Call number {}", i + 1);// 译:"叮!呼叫号码 {}" } } diff --git a/exercise/exercises/functions/functions3.rs b/exercise/exercises/functions/functions3.rs index ed5f839f..7ccff554 100644 --- a/exercise/exercises/functions/functions3.rs +++ b/exercise/exercises/functions/functions3.rs @@ -1,8 +1,9 @@ // functions3.rs -// Make me compile! Execute `rustlings hint functions3` for hints :) +// 让我能够编译!执行 `rustex hint functions3` 获取提示 :) // I AM NOT DONE +/// 翻译: [mg-chao](https://github.com/mg-chao) fn main() { call_me(); } diff --git a/exercise/exercises/functions/functions4.rs b/exercise/exercises/functions/functions4.rs index 58637e4c..a524ba96 100644 --- a/exercise/exercises/functions/functions4.rs +++ b/exercise/exercises/functions/functions4.rs @@ -1,14 +1,15 @@ // functions4.rs -// Make me compile! Execute `rustlings hint functions4` for hints :) +// 让我能够编译!执行 `rustex hint functions4` 获取提示 :) -// This store is having a sale where if the price is an even number, you get -// 10 Rustbucks off, but if it's an odd number, it's 3 Rustbucks off. +// 商店正在进行促销,如果价格是偶数,可以优惠 10 Rustbucks,如果是奇数,则优惠 3 Rustbucks。 +// 译:Rustbucks 可能想表达 Rust元 的意思,好比 美元 。 // I AM NOT DONE +/// 翻译: [mg-chao](https://github.com/mg-chao) fn main() { let original_price = 51; - println!("Your sale price is {}", sale_price(original_price)); + println!("Your sale price is {}", sale_price(original_price));// 译:"你需支付 {}" } fn sale_price(price: i32) -> { diff --git a/exercise/exercises/functions/functions5.rs b/exercise/exercises/functions/functions5.rs index d22aa6c8..fe5d8641 100644 --- a/exercise/exercises/functions/functions5.rs +++ b/exercise/exercises/functions/functions5.rs @@ -1,11 +1,12 @@ // functions5.rs -// Make me compile! Execute `rustlings hint functions5` for hints :) +// 让我能够编译!执行 `rustex hint functions5` 获取提示 :) // I AM NOT DONE +/// 翻译: [mg-chao](https://github.com/mg-chao) fn main() { let answer = square(3); - println!("The answer is {}", answer); + println!("The answer is {}", answer);// 译:"答案是 {}" } fn square(num: i32) -> i32 { diff --git a/exercise/info.toml b/exercise/info.toml index dca534de..ae0dd523 100644 --- a/exercise/info.toml +++ b/exercise/info.toml @@ -87,37 +87,35 @@ name = "functions2" path = "exercises/functions/functions2.rs" mode = "compile" hint = """ - Rust 要求函数签名有类型标注,但是 `call_me` 函数缺少 `num` 的类型注明。""" + Rust 要求函数签名(signature)有类型标注,但是 `call_me` 函数缺少 `num` 的类型标注。""" [[exercises]] name = "functions3" path = "exercises/functions/functions3.rs" mode = "compile" hint = """ -This time, the function *declaration* is okay, but there's something wrong -with the place where we're calling the function.""" +此时, 函数 *声明(declaration)* 是没问题的,但函数调用出了问题""" [[exercises]] name = "functions4" path = "exercises/functions/functions4.rs" mode = "compile" hint = """ -The error message points to line 14 and says it expects a type after the -`->`. This is where the function's return type should be-- take a look at -the `is_even` function for an example!""" +错误信息指向第 15 行,说希望在`->`之后有一个类型。 +那个地方标注了函数的返回类型——看看 `is_even` 函数的示例吧""" [[exercises]] name = "functions5" path = "exercises/functions/functions5.rs" mode = "compile" hint = """ -This is a really common error that can be fixed by removing one character. -It happens because Rust distinguishes between expressions and statements: expressions return -a value based on its operand, and statements simply return a () type which behaves just like `void` in C/C++ language. -We want to return a value of `i32` type from the `square` function, but it is returning a `()` type... -They are not the same. There are two solutions: -1. Add a `return` ahead of `num * num;` -2. remove `;`, make it to be `num * num`""" +这是一个非常常见的错误,可以通过删除一个字符来解决。 +发生的原因是 Rust 区分了表达式和语句:表达式根据其运算数(operand)返回一个值, +而语句仅返回一个 `()` 类型,其行为好比 C/C++ 中的 `void` 。 +我们希望 `square` 函数返回一个 `i32` 类型的值,但现在它返回的是 `()` 类型... +它们显然是不一样的。对此有两种解决方案。 +1. 在 `num * num;` 前面加上 `return` 关键字 +2. 移除 `;`,让它变成 `num * num`""" # IF From e728510bad8369b2d1aa387df549c5dab0310cd9 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 2 Jan 2022 11:19:47 +0800 Subject: [PATCH 09/13] perf --- exercise/exercises/functions/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/exercise/exercises/functions/README.md b/exercise/exercises/functions/README.md index 8e7cf63c..66cd1e36 100644 --- a/exercise/exercises/functions/README.md +++ b/exercise/exercises/functions/README.md @@ -1,6 +1,8 @@ # 函数(Functions) -在本练习,你将学习如何编写一个函数,以及 Rust 的编译器怎样对事物进行追溯(way back)。 +在本练习,你将学习如何编写一个函数,以及 Rust 编译器怎样可以对事物进行追溯(trace things way back)。 + +译:依据练习的内容,追溯的意思可能是类型推导之类的事。 ## 更多信息 From 1ae471dcf5f604577d84e0450e94a4f551ce1208 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 3 Jan 2022 09:57:25 +0800 Subject: [PATCH 10/13] update --- exercise/exercises/if/README.md | 4 ++-- exercise/exercises/if/if1.rs | 12 ++++++------ exercise/exercises/if/if2.rs | 8 ++++---- exercise/info.toml | 22 +++++++++++----------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/exercise/exercises/if/README.md b/exercise/exercises/if/README.md index 528d9886..c2e93ecd 100644 --- a/exercise/exercises/if/README.md +++ b/exercise/exercises/if/README.md @@ -1,7 +1,7 @@ # If -`if`, the most basic type of control flow, is what you'll learn here. +你将在这学习最基本的控制流(control flow)——`if` -## Further information +## 更多信息 - [Control Flow - if expressions](https://doc.rust-lang.org/book/ch03-05-control-flow.html#if-expressions) diff --git a/exercise/exercises/if/if1.rs b/exercise/exercises/if/if1.rs index 90867545..bfb4f73a 100644 --- a/exercise/exercises/if/if1.rs +++ b/exercise/exercises/if/if1.rs @@ -3,14 +3,14 @@ // I AM NOT DONE pub fn bigger(a: i32, b: i32) -> i32 { - // Complete this function to return the bigger number! - // Do not use: - // - another function call - // - additional variables - // Execute `rustlings hint if1` for hints + // 完成这个返回更大数字的函数! + // 但不允许以下方式: + // - 调用其它函数 + // - 额外变量 + // 执行 `rustex hint if1` 获取提示 } -// Don't mind this for now :) +// 暂时不要在意它 :) #[cfg(test)] mod tests { use super::*; diff --git a/exercise/exercises/if/if2.rs b/exercise/exercises/if/if2.rs index 80effbdf..b3c62167 100644 --- a/exercise/exercises/if/if2.rs +++ b/exercise/exercises/if/if2.rs @@ -1,8 +1,8 @@ // if2.rs -// Step 1: Make me compile! -// Step 2: Get the bar_for_fuzz and default_to_baz tests passing! -// Execute the command `rustlings hint if2` if you want a hint :) +// 第一步:让我能够编译! +// 第二步:bar_for_fuzz 和 default_to_baz 可以通过测试! +// 执行 `rustex hint if2` 获取提示 :) // I AM NOT DONE @@ -14,7 +14,7 @@ pub fn fizz_if_foo(fizzish: &str) -> &str { } } -// No test changes needed! +// 测试不需要更改。 #[cfg(test)] mod tests { use super::*; diff --git a/exercise/info.toml b/exercise/info.toml index 38e271e8..54be7f2a 100644 --- a/exercise/info.toml +++ b/exercise/info.toml @@ -128,23 +128,23 @@ name = "if1" path = "exercises/if/if1.rs" mode = "test" hint = """ -It's possible to do this in one line if you would like! -Some similar examples from other languages: -- In C(++) this would be: `a > b ? a : b` -- In Python this would be: `a if a > b else b` -Remember in Rust that: -- the `if` condition does not need to be surrounded by parentheses -- `if`/`else` conditionals are expressions -- Each condition is followed by a `{}` block.""" +如果你愿意的话,也可以用一行来做这件事! +其他语言中的一些类似例子: +- 在 C(++) 中会是: `a > b ? a : b` +- 在 Python 中会是: `a if a > b else b` +请记住在 Rust 中: +- `if` 的条件不需要用圆括号括起来 +- `if`/`else` 的条件是表达式 +- 每个条件后面都有一个 `{}` 块。""" [[exercises]] name = "if2" path = "exercises/if/if2.rs" mode = "test" hint = """ -For that first compiler error, it's important in Rust that each conditional -block return the same type! To get the tests passing, you will need a couple -conditions checking different input values.""" +对于第一个编译错误,在于 Rust 中的重要一点: +每个条件块(conditional block)都必须返回相同的类型。 +为了通过测试,你需要几个条件用来判断不同的输入""" # TEST 1 From e0f30d3c40aaaa5a0d78a8e3ff90f7e6da4c6ad3 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 3 Jan 2022 11:20:35 +0800 Subject: [PATCH 11/13] fix --- course-book/contents/basic/converse.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/course-book/contents/basic/converse.md b/course-book/contents/basic/converse.md index 1c6c6534..1e020997 100644 --- a/course-book/contents/basic/converse.md +++ b/course-book/contents/basic/converse.md @@ -251,7 +251,7 @@ impl Clone for Container { 前方危险,敬请绕行! -类型系统,你让开!我要自己转换这些类型,不成功便成仁!虽然本书都是关于非安全的内容,我还是希望你能仔细考虑避免使用本章讲到的内容。这是你在 Rust 中所能做到的真真正正、彻彻底底、最最可怕的非安全行为, 在这里,所有的保护机制都形同虚设。 +类型系统,你让开!我要自己转换这些类型,不成功便成仁!虽然本书大多是关于安全的内容,我还是希望你能仔细考虑避免使用本章讲到的内容。这是你在 Rust 中所能做到的真真正正、彻彻底底、最最可怕的非安全行为, 在这里,所有的保护机制都形同虚设。 先让你看看深渊长什么样,开开眼,然后你再决定是否深入: `mem::transmute`将类型`T`直接转成类型`U`,唯一的要求就是,这两个类型占用同样大小的字节数!我的天,这也算限制?这简直就是无底线的转换好吧?看看会导致什么问题: 1. 首先也是最重要的,转换后创建一个任意类型的实例会造成无法想象的混乱,而且根本无法预测。不要把`3`转换成`bool`类型,就算你根本不会去使用该`bool`类型,也不要去这样转换。 From 417b6b3981e1700d852edd718a4280f04ad30893 Mon Sep 17 00:00:00 2001 From: L1nY4n <980526724@qq.com> Date: Mon, 3 Jan 2022 14:34:07 +0800 Subject: [PATCH 12/13] typo fix --- course-book/contents/basic/compound-type/struct.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/course-book/contents/basic/compound-type/struct.md b/course-book/contents/basic/compound-type/struct.md index 7ab29995..ab14ec6a 100644 --- a/course-book/contents/basic/compound-type/struct.md +++ b/course-book/contents/basic/compound-type/struct.md @@ -1,11 +1,11 @@ # 结构体 -上一节中提到需要一个更高级的数据结构来帮助我们更好的抽象问题,结构体`strct`恰恰就是这样的复合数据结构,它是由其它数据类型组合而来。 其它语言也有类似的数据结构,不过可能有不同的名称,例如`object`、`record`等。 +上一节中提到需要一个更高级的数据结构来帮助我们更好的抽象问题,结构体`struct`恰恰就是这样的复合数据结构,它是由其它数据类型组合而来。 其它语言也有类似的数据结构,不过可能有不同的名称,例如`object`、`record`等。 结构体跟之前讲过的[元组](./tuple.md)有些相像:都是由多种类型组合而成。但是与元组不同的是,结构体可以为内部的每个字段起一个富有含义的名称。因此结构体更加灵活更加强大,你无需依赖这些字段的顺序来访问和解析它们。 ## 结构体语法 -天下无敌的剑士往往也因为他有一炳无双之剑,既然结构体这么强大,那么我们就需要给它配套一套强大的语法,让用户能更好的驾驭。 +天下无敌的剑士往往也因为他有一柄无双之剑,既然结构体这么强大,那么我们就需要给它配套一套强大的语法,让用户能更好的驾驭。 #### 定义结构体 一个结构体有几部分组成: @@ -107,7 +107,7 @@ fn build_user(email: String, username: String) -> User { > 仔细回想一下[所有权](../ownership/ownership.md#拷贝(浅拷贝))那一节的内容,我们提到了Copy特征:实现了Copy特征的类型无需所有权转移,可以直接在赋值时进行 > 数据拷贝,其中`bool`和`u64`类型就实现了`Copy`特征,因此`active`和`sign_in_count`字段在赋值给user2时,仅仅发生了拷贝,而不是所有权转移. > -> 值的注意的是:`username`所有权被转移给了`user2`,导致了`user1`无法再被使用,但是并不代表`user1`内部的字段不能被继续使用,例如: +> 值的注意的是:`username`所有权被转移给了`user2`,导致了`user1`无法再被使用,但是并不代表`user1`内部的其它字段不能被继续使用,例如: ```rust let user1 = User { From 54ed194eca5fb92fa0b00ba1a92747c049dcb1f1 Mon Sep 17 00:00:00 2001 From: sunface Date: Mon, 3 Jan 2022 16:06:34 +0800 Subject: [PATCH 13/13] add Deref --- course-book/contents/SUMMARY.md | 2 +- .../advance/smart-pointer/deref-drop.md | 1 - .../contents/advance/smart-pointer/deref.md | 297 ++++++++++++++++++ 3 files changed, 298 insertions(+), 2 deletions(-) delete mode 100644 course-book/contents/advance/smart-pointer/deref-drop.md create mode 100644 course-book/contents/advance/smart-pointer/deref.md diff --git a/course-book/contents/SUMMARY.md b/course-book/contents/SUMMARY.md index 132974db..b0c18399 100644 --- a/course-book/contents/SUMMARY.md +++ b/course-book/contents/SUMMARY.md @@ -66,7 +66,7 @@ - [格式化输出](advance/formatted-output.md) - [智能指针 doing](advance/smart-pointer/intro.md) - [Box堆对象分配](advance/smart-pointer/box.md) - - [Deref和Drop特征(todo)](advance/smart-pointer/deref-drop.md) + - [Deref解引用](advance/smart-pointer/deref.md) - [Cell todo](advance/smart-pointer/cell.md) - [Rc与RefCell(todo)](advance/smart-pointer/rc-refcell.md) - [自引用与内存泄漏(todo)](advance/smart-pointer/self-referrence.md) diff --git a/course-book/contents/advance/smart-pointer/deref-drop.md b/course-book/contents/advance/smart-pointer/deref-drop.md deleted file mode 100644 index f818d9ce..00000000 --- a/course-book/contents/advance/smart-pointer/deref-drop.md +++ /dev/null @@ -1 +0,0 @@ -# Deref和Drop特征(todo) diff --git a/course-book/contents/advance/smart-pointer/deref.md b/course-book/contents/advance/smart-pointer/deref.md new file mode 100644 index 00000000..9ac9f9b8 --- /dev/null +++ b/course-book/contents/advance/smart-pointer/deref.md @@ -0,0 +1,297 @@ +# Deref解引用 +智能指针的名称来源,主要就在于它实现了`Deref`和`Drop`特征,这两个特征可以智能地帮助我们节省使用上的负担: + +- `Deref`可以让智能指针像引用那样工作,这样你就就可以写出同时支持智能指针和引用的代码, 例如`&T` +- `Drop`允许你指定智能指针超出作用域后自动执行的代码,例如做一些数据清除等收尾工作 + +下面先来看看`Deref`特征是如何工作的。 + +## 通过`*`获取引用背后的值 +在正式讲解`Deref`之前,我们先来看下常规引用的解引用。 + + +常规引用是一个指针类型,包含了目标数据存储的内存地址。对常规引用使用`*`操作符,就可以通过解引用的方式获取到内存地址对应的数据值: +```rust +fn main() { + let x = 5; + let y = &x; + + assert_eq!(5, x); + assert_eq!(5, *y); +} +``` + +这里`y`就是一个常规引用,包含了值`5`所在的内存地址, 然后通过解引用`*y`,我们获取到了值`5`。如果你试图执行`assert_eq!(5, y);`,代码就会无情报错,因为你无法将一个引用与一个数值做比较: +```console +error[E0277]: can't compare `{integer}` with `&{integer}` //无法将{integer} 与&{integer}进行比较 + --> src/main.rs:6:5 + | +6 | assert_eq!(5, y); + | ^^^^^^^^^^^^^^^^^ no implementation for `{integer} == &{integer}` + | + = help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}` + // 你需要为{integer}实现用于比较的特征PartialEq<&{integer}> +``` + +## 智能指针解引用 +上面所说的解引用方式和其它大多数语言并无区别,但是Rust中将解引用提升到了一个新高度。考虑一下智能指针,它是一个结构体类型,如果你直接对它进行`*myStruct`,显然编译器不知道该如何办,因此我们可以为智能指针结构体实现`Deref`特征。 + +实现`Deref`后的智能指针结构体,就可以像普通引用一样,通过`*`进行解引用,例如`Box`智能指针: +```rust +fn main() { + let x = Box::new(1); + let sum = *x + 1; +} +``` + +智能指针`x`被`*`解引用为`i32`类型的值`1`,然后再进行求和。 + +#### 定义自己的智能指针 +现在,让我们一起来实现一个智能指针,功能上类似`Box`。由于`Box`本身很简单,并没有包含类如长度、最大长度等信息,因此用一个元组结构体即可。 + +```rust +struct MyBox(T); + +impl MyBox { + fn new(x: T) -> MyBox { + MyBox(x) + } +} +``` + +跟`Box`一样,我们的智能指针也持有一个`T`类型的值,然后使用关联函数`MyBox::new`来创建智能指针。由于还未实现`Deref`特征,此时使用`*`肯定会报错: +```rust +fn main() { + let y = MyBox::new(5); + + assert_eq!(5, *y); +} +``` + +运行后,报错如下: +```console +error[E0614]: type `MyBox<{integer}>` cannot be dereferenced + --> src/main.rs:12:19 + | +12 | assert_eq!(5, *y); + | ^^ +``` + +##### 为智能指针实现Deref特征 +现在来为`MyBox`实现`Deref`特征, 以支持`*`解引用操作符: +```rust +use std::ops::Deref; + +impl Deref for MyBox { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +``` + +很简单,当解引用`MyBox`智能指针时,返回元组结构体中的元素`&self.0`, 有几点要注意的: + +- 为了可读性, 我们声明了关联类型`Target` +- `deref`返回的是一个常规引用,可以被`*`进行解引用 + +之前报错的代码此时已能顺利编译通过。当然,标准库实现的智能指针要考虑很多边边角角情况,肯定比我们的实现要复杂。 + +## `*`背后的原理 +当我们对智能指针`Box`进行解引用时, 实际上Rust为我们调用了以下方法: +```rust +*(y.deref()) +``` + +首先调用`deref`方法返回值的常规引用,然后通过`*`对常规引用进行解引用,最终获取到目标值。 + +至于Rust为何要使用这个有点啰嗦的方式实现,原因是因为所有权系统的存在。如果`deref`方法直接返回一个值,而不是引用,那么该值的所有权将被转移给调用者,而我们不希望调用者仅仅只是`*T`一下,就拿走了智能指针中包含的值。 + +需要注意的是,`*`不会无限递归替换,从`*y`到`*(y.deref())`只会发生一次,而不会继续进行替换然后产生形如`*((y.deref()).deref())`的怪物。 + + +## 函数和方法中的隐式Deref转换 +在函数和方法中,Rust提供了一个极其有用的隐式转换:`Deref`转换。简单来说,当一个实现了`Deref`特征的值被传给函数或方法时,会根据函数参数的要求,来决定使用该值原本的类型还是`Deref`后的类型,例如: +```rust +fn main() { + let s = String::from("hello world"); + display(&s) +} + +fn display(s: &str) { + println!("{}",s); +} +``` + +以上代码有几点值得注意: + +- `String`实现了`Deref`特征,能被转换成一个`&str` +- `s`是一个`String`类型,当它被传给`display`函数时,自动通过`Deref`转换成了`&str` +- 必须使用`&s`的方式来触发`Deref` + +#### 连续的隐式Deref转换 +如果你以为`Deref`仅仅这点作用,那就大错特错了。`Deref`可以支持连续的隐式转换,直到找到适合的形式为止: +```rust +fn main() { + let s = MyBox::new(String::from("hello world")); + display(&s) +} + +fn display(s: &str) { + println!("{}",s); +} +``` + +这里我们使用了之前自定义的智能指针`MyBox`,并将其通过连续的隐式转换变成`&str`类型:首先`MyBox`被`Deref`成`String`类型,结果并不能满足`display`函数参数的要求,编译器发现`String`还可以继续`Deref`成`&str`,最终成功的匹配了函数参数。 + +想象一下,假如`Rust`没有提供这种隐式转换,我们该如何调用`display`函数? +```rust +fn main() { + let m = MyBox::new(String::from("Rust")); + hello(&(*m)[..]); +} +``` + +结果不言而喻,肯定是`&s`的方式优秀的多。总之,当参与其中的类型定义了`Deref`特征时,Rust会分析该类型并且连续使用`Deref`直到最终获得一个引用来匹配函数或者方法的参数类型,这种行为完全不会造成任何的性能损耗, 因为完全是在编译期完成。 + +但是`Deref`并不是没有缺点,缺点就是:如果你不知道某个类型实现了`Deref`特征,那么在看到某段代码时,并不能在第一时间反应过来该代码发生了隐式的`Deref`转换。事实上,不仅仅是`Deref`,在Rust中还有各种`From/Into`等等会给阅读代码带来一定负担的特征。还是那句话,一切选择都是权衡,有得必有失,得了代码的简洁性,往往就失去了可读性,Go语言就是一个刚好相反的例子。 + +再来看一下在方法、赋值中自动应用`Deref`的例子: +```rust +fn main() { + let s = MyBox::new(String::from("hello, world")); + let s1:&str = &s; + let s2: String = s.to_string(); +} +``` + +对于`s1`,我们通过两次`Deref`将`&str`类型的值赋给了它;而对于`s2`,我们在其上直接调用方法`to_string`, 实际上`MyBox`根本没有没有实现该方法,能调用`to_string`,完全是因为编译器对`MyBox`应用了`Deref`的结果。 + +## Deref规则总结 +在上面,我们零碎的介绍了不少关于`Deref`特征的知识,下面来通过较为正式的方式来对其规则进行下总结。 + +一个类型为`T`的对象`foo`,如果`T: Deref`,那么,相关`foo`的引用`&foo`在应用的时候会自动转换`&U`。 + +粗看这条规则,貌似有点类似于`AsRef`,而跟`解引`似乎风马牛不相及, 实际里面里面有些玄妙之处。 + +Rust编译器会在做`*v`操作的时候,自动先把`v`做引用归一化操作,即转换成内部通用引用的形式`&v`,整个表达式就变成 `*&v`。这里面有两种情况: + +1. 把智能指针(比如在库中定义的,Box, Rc, Arc, Cow 等),去掉壳,转成内部标准形式`&v`; +2. 把多重`&` (比如:`&&&&&&&v`),简化成`&v`(通过插入足够数量的`*`进行解引)。 +所以,它实际上在解引用之前做了一个引用的归一化操作。 + +为什么要转呢? 因为编译器设计的能力是,只能够对 &v 这种引用进行解引用。其它形式的它不认识,所以要做引用归一化操作。 + +使用引用进行过渡也是为了能够防止不必要的拷贝。 + +下面举一些例子: +```rust + fn foo(s: &str) { + // borrow a string for a second + } + + // String implements Deref + let owned = "Hello".to_string(); + + // therefore, this works: + foo(&owned); +``` + +因为`String`实现了`Deref`。 + +```rust + use std::rc::Rc; + + fn foo(s: &str) { + // borrow a string for a second + } + + // String implements Deref + let owned = "Hello".to_string(); + let counted = Rc::new(owned); + + // therefore, this works: + foo(&counted); +``` + +因为`Vec` 实现了`Deref`。 + +```rust + struct Foo; + + impl Foo { + fn foo(&self) { println!("Foo"); } + } + + let f = &&Foo; + + f.foo(); + (&f).foo(); + (&&f).foo(); + (&&&&&&&&f).foo(); +``` + +## 三种Deref转换 +在之前,我们讲的都是不可变的`Deref`转换,实际上Rust还支持将一个可变的引用转换成另一个可变的引用以及将一个可变引用转换成不可变的引用,规则如下: +- 当`T: Deref`,可以将`&T`转换成`&U`,也就是我们之前看到的例子 +- 当`T: DerefMut`,可以将`&mut T`转换成`&mut U` +- 当`T: Deref`,可以将`&mut T`转换成`&U` + +来看一个关于`DerefMut`的例子: +```rust +struct MyBox { + v: T +} + +impl MyBox { + fn new(x: T) -> MyBox { + MyBox{ + v: x + } + } +} + +use std::ops::Deref; + +impl Deref for MyBox { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.v + } +} + +use std::ops::DerefMut; + +impl DerefMut for MyBox { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.v + } +} + +fn main() { + let mut s = MyBox::new(String::from("hello, ")); + display(&mut s) +} + +fn display(s: &mut String) { + s.push_str("world"); + println!("{}",s); +} +``` + +以上代码有几点值得注意: + +- 要实现`DerefMut`必须要先实现`Deref`特征: `pub trait DerefMut: Deref {` +- `T: DerefMut`解读:将`&mut T`类型通过`DerefMut`特征的方法转换为`&mut U`类型,对应上例中,就是将`&mut MyBox`转换为`&mut String` + +对于上述三条规则中的第三条,它比另外两条稍微复杂了点:Rust可以把可变引用隐式的转换成不可变引用,但反之则不行。 + +如果从Rust的所有权和借用规则的角度考虑,当你拥有一个可变的引用,那该引用肯定是对应数据的唯一借用,那么此时将可变引用变成不可变引用并不会破坏借用规则;但是如果你拥有一个不可变引用,那同时可能还存在其它几个不可变的引用,如果此时将其中一个不可变引用转换成可变引用,就变成了可变引用与不可变引用的共存,最终破坏了借用规则。 + + +## 总结 +`Deref`可以说是Rust中最常见的隐式类型转换,而且它可以连续的实现如`Box -> String -> &str`的隐式转换,只要链条上的类型实现了`Deref`特征。 + +我们也可以为自己的类型实现`Deref`特征, 但是原则上来说,只应该为自定义的智能指针实现`Deref`。例如,虽然你可以为自己的自定义数组类型实现`Deref`以避免`myArr.0[0]`的使用形式,但是Rust官方并不推荐这么做,特别是在你开发三方库时。 \ No newline at end of file