Skip to content

Commit ad32256

Browse files
committed
borrowing_exerci = "0.3.53"
1 parent 6598c01 commit ad32256

File tree

106 files changed

+3226
-783
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+3226
-783
lines changed

docs/zh-first-volumn/src/SUMMARY.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@
5555
- [应用篋:循环`for`语句不可变借用实例](./hello-borrowing/borrowing-for-loop.md)
5656
- [关键词`ref`与引用符`&`](./hello-borrowing/ref_and.md)
5757
- [软件篋borrowing_exerci(二)](./hello-mut-borrowing/README.md)
58-
- [关于应用篋mut_borrowing_exerci](./hello-mut-borrowing/about.md)
5958
- [应用篋:借用次数实例](./hello-mut-borrowing/borrowing-count.md)
59+
- [应用篋:绑定引用的固定对象借用实例](./hello-mut-borrowing/borrowing-immut.md)
60+
- [应用篋:作为函数参数对象的生命周期](./hello-mut-borrowing/borrowing-mut-fn.md)
61+
- [应用篋:绑定引用的可变对象借用实例](./hello-mut-borrowing/borrowing-mut.md)
6062
- [应用篋:宏`dbg!`与可变实例](./hello-mut-borrowing/borrowing-dbg.md)
61-
- [应用篋:可变大小类型借用实例](./hello-mut-borrowing/borrowing-mut.md)
62-
- [应用篋:可变引用对象参数的函数借用实例](./hello-mut-borrowing/borrowing-mut-fn.md)
6363
- [应用篋:循环`for`语句可变借用实例](./hello-mut-borrowing/borrowing-for-loop-mut.md)
6464
- [题外话:使用工具cargo](./hello-mut-borrowing/crates.md)
6565
- [软件篋some_exerci](./hello-some/README.md)

docs/zh-first-volumn/src/hello-borrowing/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
66
# 软件篋borrowing_exerci(一)
77

8+
  借用和所有权机制的基本思想很简单。每个值都由一个对象拥有,在一个时刻只能由一个对象拥有,并且当对象超出范围时,该值将从内存中删除。只能借用该对象,而不能拥有该对象的所有权,但是可以创建引用对象拥有该对象值的指针,引用对象拥有该对象值的所有权,但是该对象可以随时收回其所有权。
9+
810
## 软件篋borrowing_exerci
911

1012
  Rust语言的借用机制是其最主要的特点。通过实现借用方法,使得代码更加安全和可靠。
@@ -37,4 +39,4 @@
3739
- [the-basics-of-rust-structs](https://facility9.com/2016/04/the-basics-of-rust-structs/)
3840
- [a-single-command-to-compile-and-run-rust-programs](http://blog.joncairns.com/2015/10/a-single-command-to-compile-and-run-rust-programs/)
3941
- [how-to-execute-rust-code-directly-on-unix-systems-using-the-shebang](https://stackoverflow.com/questions/41322300/how-to-execute-rust-code-directly-on-unix-systems-using-the-shebang)
40-
-
42+
- [rust-ownership](https://hellocode.dev/rust-ownership)
-76 Bytes
Loading
Binary file not shown.
-6.34 KB
Loading
Binary file not shown.

docs/zh-first-volumn/src/hello-mut-borrowing/about.md

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# 应用篋:绑定引用的固定对象借用实例
2+
3+
  从可变对象(mutable variable)出发,其引用方式,使用两种不同的借用方式:固定引用(immutable reference)和可变引用(mutable reference)。本节将解释把固定和可变引用绑定到固定对象的借用方式。尤其是当固定对象与固定和可变引用交互在一起时,程序代码将会比较更复杂一些。但是通过这一节学习可以加深对借用对象的生命周期概念的理解。
4+
5+
## 学习内容
6+
- 了解和学习把固定和可变引用绑定到固定对象的借用实例
7+
8+
## 篇目
9+
  
10+
- [绑定固定引用的固定对象](#绑定固定引用的固定对象)
11+
- [绑定可变引用的固定对象](#绑定可变引用的固定对象)
12+
- [绑定不同引用的固定对象](#绑定不同引用的固定对象)
13+
- [题外话](#题外话)
14+
- [参考资料](#参考资料)
15+
16+
## 绑定固定引用的固定对象
17+
18+
> let immut_and_immut_ref = &immut_instance;
19+
>
20+
> let immut_and_immut_ref = &mut_instance;
21+
22+
![image](../../hello-borrowing/images/hello_borrowing-17-mut_ref.png)
23+
24+
  上面示意图说明了下面程序可变对象`mut_instance`及其固定引用的对象`immut_ref`(下面简称为“固定引用的固定对象”或者”引用固定对象“)的生命周期。左边图一直可以使用到它们的生命周期结束,这是下面程序的情况。图上带箭头的连接线,是程序代码顺序,而图上无箭头的连接线说明了对象的生命周期范围。
25+
26+
```rust
27+
{{ #include ../../../../hello-borrowing/bin-hello/examples/mut_var_sized/string_ref.rs:feature-ok }}
28+
```
29+
30+
  另外一种情况,就是右边示意图,当可变对象`mut_instance`需要拿回所有权之时,也是引用固定对象`immut_ref`生命周期结束之时。要是还想使用已经结束生命周期的对象`immut_ref`,编译器就会告诉我们这是不可以的。在之后的其他实例说明过程中,不再说明左边图的情况,主要说明右边示意图的情况。
31+
32+
```rust
33+
{{ #include ../../../../hello-borrowing/bin-hello/examples/mut_var_sized/string_ref.rs:feature-error_02 }}
34+
```
35+
36+
  要是上面程序,在对象`mut_instance`需要拿回所有权以后,不再使用对象`immut_ref`,程序一切正常。
37+
38+
  下面程序说明了这种直接转移可变对象`mut_instance`,或者说使用对象`copy_mut_instance`,使得可变对象`mut_instance`失去其生命周期,取而代之。在对象`copy_mut_instance`取而代之以后,这样,就不再可以使用对象`mut_instance`。要是再使用它就会如下下面程序一样,出现编译错误。
39+
40+
```rust
41+
{{ #include ../../../../hello-borrowing/bin-hello/examples/mut_var_sized/string_ref.rs:feature-error_01 }}
42+
```
43+
44+
## 绑定可变引用的固定对象
45+
46+
> let immut_and_mut_ref = &mut mut_instance;
47+
48+
![image](../../hello-borrowing/images/hello_borrowing-16-mut_ref.png)
49+
50+
  上面示意图也是说明下面程序可变对象`mut_instance`及其可变引用的对象`mut_ref`(下面简称为“可变引用的固定对象”或者”引用固定对象“)`mut_ref`的生命周期。
51+
52+
  对于这种可变对象及其可变引用的固定对象情况,从借用机制上看,与上面可变类型对象的固定引用的固定对象思路是一样的,不同的是可变引用的固定对象可以修改其可变对象的值,并且修改结果直接改变到可变对象的内容。
53+
54+
```rust
55+
{{ #include ../../../../hello-borrowing/bin-hello/examples/mut_var_sized/string_ref.rs:feature-cp }}
56+
```
57+
58+
  下面程序说明了,当对象`mut_instance`拿回所有权以后,不再可以使用引用固定对象`mut_ref`了。
59+
60+
```rust
61+
{{ #include ../../../../hello-borrowing/bin-hello/examples/mut_var_sized/string_ref.rs:feature-error_03 }}
62+
```
63+
64+
## 绑定不同引用的固定对象
65+
66+
![image](../../hello-borrowing/images/hello_borrowing-14-mut_refs.png)
67+
68+
  上面示意图的左边分支说明下面程序对象`mut_instance``mut_ref``immut_ref`的生命周期。这里看到,一个可变对象涉及到其固定引用与可变引用的固定对象的使用方法。要是查看三个对象的内存地址,它们是完全相同的。
69+
70+
  下面程序是左边示意图的正确借用方法:
71+
72+
```rust
73+
{{ #include ../../../../hello-borrowing/bin-hello/examples/mut_var_sized/string_refs.rs:feature-ok }}
74+
```
75+
76+
  下面程序说明了固定对象`immut_ref`的生命周期编译错误问题:
77+
78+
```rust
79+
{{ #include ../../../../hello-borrowing/bin-hello/examples/mut_var_sized/string_refs.rs:feature-error_01 }}
80+
```
81+
82+
  下面程序说明了固定对象`mut_ref`的生命周期编译错误问题:
83+
84+
```rust
85+
{{ #include ../../../../hello-borrowing/bin-hello/examples/mut_var_sized/string_refs.rs:feature-error_02 }}
86+
```
87+
88+
  上面示意图的右边分支是另外一种可能性。上面左边和右边示意图的分支仅仅是下面代码不同。左边分支示意图的对象`immut_ref`的值取自于引用对象`mut_ref`,而右边分支示意图的对象`immut_ref`的值直接取自于`instance`的引用:
89+
90+
```rust
91+
// left side image
92+
//let immut_ref :&String = mut_ref;
93+
// right side image
94+
let immut_ref :&String = &instance;
95+
```
96+
97+
  对于这种情况,下面程序给出了对象`mut_ref`的生命周期编译错误问题:
98+
99+
```rust
100+
{{ #include ../../../../hello-borrowing/bin-hello/examples/mut_var_sized/string_refs.rs:feature-error_03 }}
101+
```
102+
103+
  下面示意图说明还有一些其他更多的可能性。
104+
105+
![image](../../hello-borrowing/images/hello_borrowing-15-mut_refs.png)
106+
107+
## 题外话
108+
109+
## 参考资料
110+
- [mutable-borrow-automatically-changes-to-immutable](https://stackoverflow.com/questions/40654940/mutable-borrow-automatically-changes-to-immutable/40655179#40655179)
111+
- [mutable-reference-in-rust](https://medium.com/@vikram.fugro/mutable-reference-in-rust-995320366e22)
Lines changed: 159 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,171 @@
1-
# 应用篋:可变引用对象参数的函数借用实例
1+
# 应用篋:作为函数参数对象的生命周期
22

3+
  本节将类型`String`对象、类型`String`引用和类型`str`作为实例,分析它们作为函数参数的生命周期。
34

45
## 学习内容
5-
- 了解和学习Rust语言可变引用对象参数的函数借用实例
6+
- 了解和学习Rust语言含可变引用参数的函数借用实例
67

78
## 篇目
8-
  
9-
- [题外话](#题外话)
10-
- [题外话](#题外话)
11-
- [题外话](#题外话)
9+
10+
- [可变类型`String`引用的生命周期](#可变类型string引用的生命周期)  
11+
- [可变类型`String`对象的生命周期](#可变类型string对象的生命周期)
12+
- [引用类型`str`对象的生命周期](#引用类型str对象的生命周期)
13+
- [引用类型`str`对象的生命周期符](#引用类型str对象的生命周期符)
1214
- [题外话](#题外话)
15+
- [类型`String`与类型`str`的区别](#类型string与类型str的区别)
1316
- [参考资料](#参考资料)
1417

1518

19+
## 可变类型`String`引用的生命周期
20+
21+
  先把下面程序的两个对象进行一下说明:
22+
23+
- 对象`instance`是类型`String`的可变对象,因为在使用`let`绑定该对象`instance`时,使用了关键词`mut`。下面将对象`instance`称之为**可变对象**
24+
- 对象`mut_ref`是可变对象`instance`的可变引用,因为在使用`&`绑定对象值时,使用了关键词`mut`。下面将对象`mut_ref`称之为**可变引用**
25+
- 对象`instance`是所有者,而对象`mut_ref`仅仅是从所有者那里租用者,它们所拥有的内容是一样的;
26+
- 在对象`mut_ref`生命周期里,它可以操作对象`instance`所拥有的所有内容。从这个意义上说,它们是完全一样的;
27+
28+
```rust
29+
{{ #include ../../../../hello-borrowing/bin-hello/examples/mut_fn/base_string.rs:feature-ok }}
30+
```
31+
32+
  上面程序的运行结果如下。从该结果可以分析该程序,无论是可变对象`instance`,还是可变引用`mut_ref`或者方法参数`input`,都是指向相同的内存地址,即可变对象`instance`的内容。这里反映了Rust语言调用函数的借用机制。
33+
34+
```
35+
───────┬──────────────────────────────────────────────────────
36+
│ STDIN
37+
───────┼──────────────────────────────────────────────────────
38+
1 │ instance = 0x7fff5a219e70
39+
2 │ mut_ref = 0x7fff5a219e70
40+
3 │ one() input = 0x7fff5a219e70
41+
4 │ two() input = 0x7fff5a219e70
42+
5 │ instance = 0x7fff5a219e70
43+
6 │ Hello, world!
44+
───────┴──────────────────────────────────────────────────────
45+
```
46+
47+
  尽管主程序里,在创建可变引用`mut_ref`以后,并没有看到对可变引用`mut_ref`或者可变对象`instance`进行赋值,但是可变对象`instance`的内容一直在变化。
48+
49+
  当方法借用可变引用`mut_ref`以后,还是归还了所有权到主程序,而不是把该可变引用`mut_ref`消费掉了。因此,第二个方法还可以继续使用该可变引用`mut_ref`
50+
51+
  通过给两个方法传递可变引用`mut_ref`,它们不仅可以借用其内容(这是因为绑定可变引用`mut_ref`时,使用了关键词`&`),而且还可以修改其内容(这是因为绑定可变引用`mut_ref`时,在`&`之后使用了关键词`mut`)。同时方法还将其内容返回到可变引用`mut_ref`,即可变对象`instance`
52+
53+
  必须指出的是,方法参数也必须是可变引用,与调用方法时的对象类型是完全一致的,不然就会出现程序编译错误。下面程序就是说明这个问题。
54+
55+
```rust
56+
{{ #include ../../../../hello-borrowing/bin-hello/examples/mut_fn/base_string.rs:feature-error_02 }}
57+
```
58+
59+
## 可变类型`String`对象的生命周期
60+
61+
  下面程序实例是将可变类型`String`对象直接作为方法参数使用,就是方法直接借用可变类型`String`对象,而不是其引用。下面实例可以正常运行,但是,它有什么问题呢?
62+
63+
```rust
64+
{{ #include ../../../../hello-borrowing/bin-hello/examples/mut_fn/base_string.rs:feature-okay }}
65+
```
66+
67+
  上面程序的运行结果如下。当可变对象`instance`作为参数传递到方法以后,该对象就被该方法消费掉了。从它们的内存地址信息可以看到,它们是不一样的。
68+
69+
```
70+
───────┬──────────────────────────────────────────────────────
71+
│ STDIN
72+
───────┼──────────────────────────────────────────────────────
73+
1 │ instance = 0x7fff53e5cf50
74+
2 │ input = 0x7fff53e5cfc0
75+
3 │ input = Hello, world
76+
───────┴──────────────────────────────────────────────────────
77+
```
78+
79+
  主程序可变对象`instance`是不是真的被方法消费掉了呢?通过编译下面程序,编译器会告诉我们答案。下面出现编译错误说明了可变对象`instance`不转移了,就是被方法消费掉了。
80+
81+
```rust
82+
{{ #include ../../../../hello-borrowing/bin-hello/examples/mut_fn/base_string.rs:feature-error_01 }}
83+
```
84+
85+
## 引用类型`str`对象的生命周期
86+
87+
  上面说明了类型`String`对象的可变引用,不仅可以被借用,而且还可以被修改。但是引用类型`str`对象只能被借用,而不能被修改。因为它不能被修改,所以它返回时还是它本身。
88+
89+
  引用类型`str`对象作为方法参数,主要目的是传递其内容。
90+
91+
```rust
92+
{{ #include ../../../../hello-borrowing/bin-hello/examples/mut_fn/base_str.rs:feature-okey }}
93+
```
94+
95+
  上面程序运行结果可以看到,尽管在方法里参数`input`调用了方法`to_ascii_uppercase()`,但是,不仅参数`input`的内存地址始终与主程序输入对象的内存地址是完全一样的,而且其内容到最后还是原来的内容。这种调用了方法`to_ascii_uppercase()`并不是修改其内容,而是创建一个新对象,在新对象里,可以看到其内容发生了变化。
96+
97+
```
98+
───────┬──────────────────────────────────────────────────────
99+
│ STDIN
100+
───────┼──────────────────────────────────────────────────────
101+
1 │ after instance change = 0x7fff5c99ce48
102+
2 │
103+
3 │ before call one instance = 0x7fff5c99ce48
104+
4 │ one() input = 0x7f94a9c00330
105+
5 │ one() ret_input = 0x7fff5c99cc70
106+
6 │ one() ret_input = HELLO
107+
7 │ one() input = 0x7f94a9c00330
108+
8 │ one() input = Hello
109+
9 │ after call one instance = 0x7fff5c99ce48
110+
10 │ instance = Hello
111+
───────┴──────────────────────────────────────────────────────
112+
```
113+
114+
## 引用类型`str`对象的生命周期符
115+
116+
  通过下面实例,将引出生命周期符的概念。下面程序编译会出现错误:"缺少生命周期符"。
117+
118+
```rust
119+
{{ #include ../../../../hello-borrowing/bin-hello/examples/mut_fn/base_str.rs:feature-error_07 }}
120+
```
121+
122+
  使用函数生命周期符,一般情况下,是因为函数返回对象存在引用对象。上面程序怎么样解决呢?下面程序将上面程序问题得到解决。之所以上面程序不能编译成功,是因为该方法存在两个引用,它们都有自己的生命周期,而结果只有一个生命周期,编译器不知道应该使用哪一个生命周期。生命周期符是统一这两个引用的生命周期。
123+
124+
```rust
125+
{{ #include ../../../../hello-borrowing/bin-hello/examples/mut_fn/base_str.rs:feature-ok }}
126+
```
127+
128+
  在上面程序里,生命周期符`'de`是由两部分:前面单引号`'`是必须的;而后面与对象命名法则(snake_case)是一样的。一般使用`'a`
16129

17130
## 题外话
18131

19-
## 参考资料
132+
### 类型`String`与类型`str`的区别
133+
134+
  字符串类型对象是可变的。而类型`str`,通常以`&str`表示对象是不可更改的,它只是对字符串的内容储存。
135+
136+
  下面程序通过两个方法`make_ascii_uppercase()``to_ascii_uppercase()`说明,两种类型对象使用时的区别。方法`make_ascii_uppercase()`是直接修改其对象内容,得到其结果;而方法`to_ascii_uppercase()`并不是直接修改本身引用对象,而是创建了一个新类型`String`对象作为返回结果。
137+
138+
```rust
139+
fn main () {
140+
let mut instance = String::from("Hello");
141+
println!("instance = {:p}", &instance);
142+
instance.make_ascii_uppercase();
143+
println!("{}", instance);
144+
println!("instance = {:p}", &instance);
145+
println!();
146+
147+
let instance = "Hello";
148+
println!("instance = {:p}", instance);
149+
instance.to_ascii_uppercase();
150+
println!("instance = {}", instance);
151+
println!();
152+
153+
let instance = "Hello";
154+
println!("instance = {:p}", instance);
155+
let ret_instance = instance.to_ascii_uppercase();
156+
println!("instance = {}", instance);
157+
println!("ret_instance = {:p}", &ret_instance);
158+
println!("ret_instance = {}", ret_instance);
159+
}
160+
```
161+
162+
163+
164+
## 参考资料
165+
- [rust-ownership](https://hellocode.dev/rust-ownership)
166+
- [how-can-i-create-a-static-string-in-rust](https://stackoverflow.com/questions/55977067/how-can-i-create-a-static-string-in-rust)
167+
- [what-are-the-differences-between-rusts-string-and-str](https://stackoverflow.com/questions/24158114/what-are-the-differences-between-rusts-string-and-str)
168+
- [rust-lifetimes-a-high-wall-for-rust-newbies](https://dev.to/takaakifuruse/rust-lifetimes-a-high-wall-for-rust-newbies-3ap)
169+
- [book lifetimes](https://doc.rust-lang.org/1.9.0/book/lifetimes.html)
170+
- [book naming](https://doc.rust-lang.org/1.0.0/style/style/naming/README.html)
171+

0 commit comments

Comments
 (0)