You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/ch04-02-references-and-borrowing.md
+4-4Lines changed: 4 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -75,7 +75,7 @@ References are **non-owning pointers**, because they do not own the data they po
75
75
The previous examples using boxes and strings have not shown how Rust "follows" a pointer to its data. For example, the `println!` macro has mysteriously worked for both owned strings of type `String`, and for string references of type `&String`. The underlying mechanism is the **dereference** operator, written with an asterisk (`*`). For example, here's a program that uses dereferences in a few different ways:
76
76
77
77
```aquascope,interpreter
78
-
#fn main() {
78
+
#fn main() {
79
79
let mut x: Box<i32> = Box::new(1);
80
80
let a: i32 = *x; // *x reads the heap value, so a = 1
81
81
*x += 1; // *x on the left-side modifies the heap value,
@@ -86,15 +86,15 @@ let b: i32 = **r1; // two dereferences get us to the heap value
86
86
87
87
let r2: &i32 = &*x; // r2 points to the heap value directly
88
88
let c: i32 = *r2;`[]` // so only one dereference is needed to read it
89
-
#}
89
+
#}
90
90
```
91
91
92
92
Observe the difference between `r1` pointing to `x` on the stack, and `r2` pointing to the heap value `2`.
93
93
94
94
You probably won't see the dereference operator very often when you read Rust code. Rust implicitly inserts dereferences and references in certain cases, such as calling a method with the dot operator. For example, this program shows two equivalent ways of calling the [`i32::abs`](https://doc.rust-lang.org/std/primitive.i32.html#method.abs) (absolute value) and [`str::len`](https://doc.rust-lang.org/std/primitive.str.html#method.len) (string length) functions:
95
95
96
96
```rust,ignore
97
-
#fn main() {
97
+
#fn main() {
98
98
let x: Box<i32> = Box::new(-1);
99
99
let x_abs1 = i32::abs(*x); // explicit dereference
100
100
let x_abs2 = x.abs(); // implicit dereference
@@ -109,7 +109,7 @@ let s = String::from("Hello");
109
109
let s_len1 = str::len(&s); // explicit reference
110
110
let s_len2 = s.len(); // implicit reference
111
111
assert_eq!(s_len1, s_len2);
112
-
#}
112
+
#}
113
113
```
114
114
115
115
This example shows implicit conversions in three ways:
Copy file name to clipboardExpand all lines: src/ch04-03-fixing-ownership-errors.md
+10-10Lines changed: 10 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -284,34 +284,34 @@ In sum, **if a value does not own heap data, then it can be copied without a mov
284
284
So if we have a vector of non-`Copy` types like `String`, then how do we safely get access to an element of the vector? Here's a few different ways to safely do so. First, you can avoid taking ownership of the string and just use an immutable reference:
285
285
286
286
```rust,ignore
287
-
#fn main() {
287
+
#fn main() {
288
288
let v: Vec<String> = vec![String::from("Hello world")];
289
289
let s_ref: &String = &v[0];
290
290
println!("{s_ref}!");
291
-
#}
291
+
#}
292
292
```
293
293
294
294
Second, you can clone the data if you want to get ownership of the string while leaving the vector alone:
295
295
296
296
```rust,ignore
297
-
#fn main() {
297
+
#fn main() {
298
298
let v: Vec<String> = vec![String::from("Hello world")];
299
299
let mut s: String = v[0].clone();
300
300
s.push('!');
301
301
println!("{s}");
302
-
#}
302
+
#}
303
303
```
304
304
305
305
Finally, you can use a method like [`Vec::remove`] to move the string out of the vector:
306
306
307
307
```rust,ignore
308
-
#fn main() {
308
+
#fn main() {
309
309
let mut v: Vec<String> = vec![String::from("Hello world")];
310
310
let mut s: String = v.remove(0);
311
311
s.push('!');
312
312
println!("{s}");
313
313
assert!(v.len() == 0);
314
-
#}
314
+
#}
315
315
```
316
316
317
317
@@ -424,24 +424,24 @@ error[E0502]: cannot borrow `a[_]` as immutable because it is also borrowed as m
424
424
Again, **this program is safe.** For cases like these, Rust often provides a function in the standard library that can work around the borrow checker. For example, we could use [`slice::split_at_mut`][split_at_mut]:
425
425
426
426
```rust,ignore
427
-
#fn main() {
427
+
#fn main() {
428
428
let mut a = [0, 1, 2, 3];
429
429
let (a_l, a_r) = a.split_at_mut(2);
430
430
let x = &mut a_l[1];
431
431
let y = &a_r[0];
432
432
*x += *y;
433
-
#}
433
+
#}
434
434
```
435
435
436
436
You might wonder, but how is `split_at_mut` implemented? In some Rust libraries, especially core types like `Vec` or `slice`, you will often find **`unsafe` blocks**. `unsafe` blocks allow the use of "raw" pointers, which are not checked for safety by the borrow checker. For example, we could use an unsafe block to accomplish our task:
437
437
438
438
```rust,ignore
439
-
#fn main() {
439
+
#fn main() {
440
440
let mut a = [0, 1, 2, 3];
441
441
let x = &mut a[1] as *mut i32;
442
442
let y = &a[2] as *const i32;
443
443
unsafe { *x += *y; } // DO NOT DO THIS unless you know what you're doing!
444
-
#}
444
+
#}
445
445
```
446
446
447
447
Unsafe code is sometimes necessary to work around the limitations of the borrow checker. As a general strategy, let's say the borrow checker rejects a program you think is actually safe. Then you should look for standard library functions (like `split_at_mut`) that contain `unsafe` blocks which solve your problem. We will discuss unsafe code further in [Chapter 20][unsafe]. For now, just be aware that unsafe code is how Rust implements certain otherwise-impossible patterns.
0 commit comments