diff --git a/solutions/basic-types/functions.md b/solutions/basic-types/functions.md index e01ddd3..294b5fb 100644 --- a/solutions/basic-types/functions.md +++ b/solutions/basic-types/functions.md @@ -92,6 +92,13 @@ fn never_return_fn() -> ! { } ``` +```rust +// IMPLEMENT this function in THREE ways +fn never_return_fn() -> ! { + todo!(); +} +``` + ```rust // IMPLEMENT this function in THREE ways fn never_return_fn() -> ! { diff --git a/solutions/ownership/ownership.md b/solutions/ownership/ownership.md index 1cd5f74..da93530 100644 --- a/solutions/ownership/ownership.md +++ b/solutions/ownership/ownership.md @@ -96,6 +96,17 @@ fn print_str(s: String) { } ``` +```rust + fn main() { + let s = String::from("hello, world"); + print_str(&s); + println!("{}", s); + } + fn print_str(s: &String) { + println!("{}",s) + } + ``` + 5. ```rust @@ -157,4 +168,4 @@ fn main() { println!("{:?}, {:?}, {:?}", s1, s2, t); // -> "hello", "world", ("hello", "world") } -``` \ No newline at end of file +``` diff --git a/zh-CN/src/lifetime/advance.md b/zh-CN/src/lifetime/advance.md index cba2b30..7331755 100644 --- a/zh-CN/src/lifetime/advance.md +++ b/zh-CN/src/lifetime/advance.md @@ -1,3 +1,285 @@ -# advance +# 深入生命周期 -aaaa \ No newline at end of file +## 特征约束 +就像泛型类型可以有约束一样,生命周期也可以有约束 ,如下所示: +- `T: 'a`,所有引用在 `T` 必须超过生命周期 `'a` +- `T: Trait + 'a`: `T` 必须实现特征 `Trait` 并且所有引用在 `T` 必须超过生命周期 `'a` + +**示例** +```rust,editable +use std::fmt::Debug; // 特征约束使用 + +#[derive(Debug)] +struct Ref<'a, T: 'a>(&'a T); +// `Ref` 包含对泛型类型 `T` 的引用,该泛型类型具有 +// 未知的生命周期 `'a`. `T` 是约定任何 +// 引用在 `T` 必须大于 `'a` 。此外,在生命周期 +// 里 `Ref` 不能超过 `'a`。 + +// 使用 `Debug` 特征打印的通用函数。 +fn print(t: T) where + T: Debug { + println!("`print`: t is {:?}", t); +} + +// 这里引用 `T` 使用 where `T` 实现 +// `Debug` 和所有引用 `T` 都要比 `'a` 长 +// 此外,`'a`必须要比函数声明周期长 +fn print_ref<'a, T>(t: &'a T) where + T: Debug + 'a { + println!("`print_ref`: t is {:?}", t); +} + +fn main() { + let x = 7; + let ref_x = Ref(&x); + + print_ref(&ref_x); + print(ref_x); +} +``` + +1、🌟 +```rust,editable +/* 使用生命周期注释结构体 +1. `r` 和 `s` 必须是不同生命周期 +2. `s` 的生命周期需要大于 'r' +*/ +struct DoubleRef { + r: &T, + s: &T +} +fn main() { + println!("Success!") +} +``` + + +2、🌟🌟 +```rust,editable +/* 添加类型约束使下面代码正常运行 */ +struct ImportantExcerpt<'a> { + part: &'a str, +} + +impl<'a, 'b> ImportantExcerpt<'a> { + fn announce_and_return_part(&'a self, announcement: &'b str) -> &'b str { + println!("Attention please: {}", announcement); + self.part + } +} + +fn main() { + println!("Success!") +} +``` + +3、🌟🌟 +```rust,editable +/* 添加类型约束使下面代码正常运行 */ +fn f<'a, 'b>(x: &'a i32, mut y: &'b i32) { + y = x; + let r: &'b &'a i32 = &&0; +} + +fn main() { + println!("Success!") +} +``` + +## HRTB(更高等级特征约束)(Higher-ranked trait bounds) +类型约束可能在生命周期中排名更高。这些约束指定了一个约束对于所有生命周期都为真。例如,诸如此类的约束 `for<'a> &'a T: PartialEq` 需要如下实现: + +```rust +impl<'a> PartialEq for &'a T { + // ... +} +``` + +然后可以用于将一个 `&'a T` 与任何生命周期进行比较 `i32` 。 + +这里只能使用更高级别的约束,因为引用的生命周期比函数上任何可能的生命周期参数都短。 + +4、🌟🌟🌟 +```rust +/* 添加 HRTB 使下面代码正常运行! */ +fn call_on_ref_zero<'a, F>(f: F) where F: Fn(&'a i32) { + let zero = 0; + f(&zero); +} + +fn main() { + println!("Success!") +} +``` +## NLL(非词汇生命周期)(Non-Lexical Lifetime) +在解释 NLL 之前,我们先看一段代码: +```rust +fn main() { + let mut s = String::from("hello"); + + let r1 = &s; + let r2 = &s; + println!("{} and {}", r1, r2); + + let r3 = &mut s; + println!("{}", r3); +} +``` + +根据我们目前的知识,这段代码会因为违反 Rust 中的借用规则而导致错误。 + +但是,如果您执行 `cargo run` ,那么一切都没问题,那么这里发生了什么? + +编译器在作用域结束之前判断不再使用引用的能力称为 **非词法生命周期**(简称 **NLL** )。 + +有了这种能力,编译器就知道最后一次使用引用是什么时候,并根据这些知识优化借用规则。 + +```rust +let mut u = 0i32; +let mut v = 1i32; +let mut w = 2i32; + +// lifetime of `a` = α ∪ β ∪ γ +let mut a = &mut u; // --+ α. lifetime of `&mut u` --+ lexical "lifetime" of `&mut u`,`&mut u`, `&mut w` and `a` +use(a); // | | +*a = 3; // <-----------------+ | +... // | +a = &mut v; // --+ β. lifetime of `&mut v` | +use(a); // | | +*a = 4; // <-----------------+ | +... // | +a = &mut w; // --+ γ. lifetime of `&mut w` | +use(a); // | | +*a = 5; // <-----------------+ <--------------------------+ +``` + +## 再借用 + +学习了 NLL 之后,我们现在可以很容易地理解再借用了。 + +**示例** +```rust +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} + +impl Point { + fn move_to(&mut self, x: i32, y: i32) { + self.x = x; + self.y = y; + } +} + +fn main() { + let mut p = Point { x: 0, y: 0 }; + let r = &mut p; + // 这里是再借用 + let rr: &Point = &*r; + + println!("{:?}", rr); // 这里结束再借用 + + // 再借用结束,现在我们可以继续使用 `r` + r.move_to(10, 10); + println!("{:?}", r); +} +``` + + +5、🌟🌟 +```rust,editable +/* 通过重新排序一些代码使下面代码正常运行 */ +fn main() { + let mut data = 10; + let ref1 = &mut data; + let ref2 = &mut *ref1; + + *ref1 += 1; + *ref2 += 2; + + println!("{}", data); +} +``` + + +## 未约束的生命周期 +在 [Nomicon - Unbounded Lifetimes](https://doc.rust-lang.org/nomicon/unbounded-lifetimes.html) 中查看更多信息。 + + +## 更多省略规则 + +```rust +impl<'a> Reader for BufReader<'a> { + // 'a 在以下方法中不使用 +} + +// 可以写为: +impl Reader for BufReader<'_> { + +} +``` + +```rust +// Rust 2015 +struct Ref<'a, T: 'a> { + field: &'a T +} + +// Rust 2018 +struct Ref<'a, T> { + field: &'a T +} +``` + + +## 艰难的练习 + +6、🌟🌟🌟🌟 +```rust +/* 使下面代码正常运行 */ +struct Interface<'a> { + manager: &'a mut Manager<'a> +} + +impl<'a> Interface<'a> { + pub fn noop(self) { + println!("interface consumed"); + } +} + +struct Manager<'a> { + text: &'a str +} + +struct List<'a> { + manager: Manager<'a>, +} + +impl<'a> List<'a> { + pub fn get_interface(&'a mut self) -> Interface { + Interface { + manager: &mut self.manager + } + } +} + +fn main() { + let mut list = List { + manager: Manager { + text: "hello" + } + }; + + list.get_interface().noop(); + + println!("Interface should be dropped here and the borrow released"); + + use_list(&list); +} + +fn use_list(list: &List) { + println!("{}", list.manager.text); +} +``` diff --git a/zh-CN/src/ownership/ownership.md b/zh-CN/src/ownership/ownership.md index c329806..3b12d00 100644 --- a/zh-CN/src/ownership/ownership.md +++ b/zh-CN/src/ownership/ownership.md @@ -123,7 +123,7 @@ fn main() { }; // 通过这种解构式模式匹配,person.name 的所有权被转移给新的变量 `name` - // 但是,这里 `age` 变量确是对 person.age 的引用, 这里 ref 的使用相当于: let age = &person.age + // 但是,这里 `age` 变量却是对 person.age 的引用, 这里 ref 的使用相当于: let age = &person.age let Person { name, ref age } = person; println!("The person's age is {}", age);