Skip to content

Commit 6e422aa

Browse files
committed
update original
1 parent c6cdf84 commit 6e422aa

8 files changed

Lines changed: 210 additions & 1 deletion

File tree

rust-cookbook/ci/dictionary.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@ readline
277277
recusively
278278
recv
279279
RecvError
280+
refcell
281+
RefCell
280282
regex
281283
Regex
282284
REGEX

rust-cookbook/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
- [Processor](hardware/processor.md)
5959
- [Memory Management](mem.md)
6060
- [Global Static](mem/global_static.md)
61+
- [Smart Pointers](mem/smart_pointers.md)
6162
- [Network](net.md)
6263
- [TCP](net/tcp.md)
6364
- [UDP](net/udp.md)

rust-cookbook/src/mem.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,18 @@
66
| [Std::cell][ex-std-oncecell] | [![std-badge]][std] | [![cat-caching-badge]][cat-caching] [![cat-rust-patterns-badge]][cat-rust-patterns] |
77
| [`std::cell:LazyCell`][ex-std-lazycell] | [![std-badge]][std] | [![cat-caching-badge]][cat-caching] [![cat-rust-patterns-badge]][cat-rust-patterns] |
88
| [`std::sync::LazyLock`][ex-std-lazylock] | [![std-badge]][std] | [![cat-caching-badge]][cat-caching] [![cat-rust-patterns-badge]][cat-rust-patterns] |
9+
| [Store different types in one vector with `Box<dyn Trait>`][ex-std-box] | [![std-badge]][std] | [![cat-rust-patterns-badge]][cat-rust-patterns] |
10+
| [Share mutable structure between owners with `Rc<RefCell<T>>`][ex-std-rc-refcell] | [![std-badge]][std] | [![cat-rust-patterns-badge]][cat-rust-patterns] |
11+
| [Return borrowed or owned text with `Cow<str>`][ex-std-cow] | [![std-badge]][std] | [![cat-rust-patterns-badge]][cat-rust-patterns] |
12+
| [Update text using `mem::swap`, `mem::take` and `mem::replace`][ex-std-mem] | [![std-badge]][std] | [![cat-rust-patterns-badge]][cat-rust-patterns] |
913

1014
[ex-lazy-constant]: mem/global_static.html#declare-lazily-evaluated-constant
1115
[ex-std-oncecell]: mem/global_static.html#stdcell
1216
[ex-std-lazycell]: mem/global_static.html#stdcelllazycell
1317
[ex-std-lazylock]: mem/global_static.html#stdsynclazylock
14-
18+
[ex-std-box]: mem/smart_pointers.html#store-different-types-in-one-vector-with-box
19+
[ex-std-rc-refcell]: mem/smart_pointers.html#share-mutable-structure-between-owners-with-rc-and-refcell
20+
[ex-std-cow]: mem/smart_pointers.html#return-borrowed-or-owned-text-with-cow
21+
[ex-std-mem]: mem/smart_pointers.html#update-text-using-swap-take-and-replace
1522

1623
{{#include links.md}}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Smart Pointers
2+
3+
{{#include smart_pointers/box_store_mixed_types.md}}
4+
{{#include smart_pointers/rc_refcell.md}}
5+
{{#include smart_pointers/cow_string_processing.md}}
6+
{{#include smart_pointers/swap_or_replace_mem.md}}
7+
8+
{{#include ../links.md}}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
## Store different types in one vector with `Box`
2+
[![std-badge]][std] [![cat-rust-patterns-badge]][cat-rust-patterns]
3+
4+
Defines the trait `Notification` that requires the implementation of the function `send(&self)`. Implement `Notification` trait for `Email` and `Sms`.
5+
Creates a vector that holds different types that implement the same trait `Notification` and [`Box<T>`]. Iterate over that vector calling the method `send(&self)`.
6+
7+
Trait objects such as `dyn Notification` do not have a size known at compile time, so they cannot be stored directly by value. [`Box<T>`] stores the value behind
8+
a pointer with a known size, making it possible to use different `Notification` implementations.
9+
10+
```rust,edition2021
11+
trait Notification {
12+
fn send(&self);
13+
}
14+
15+
struct Email {
16+
address: String,
17+
}
18+
19+
struct Sms {
20+
phone_number: String,
21+
}
22+
23+
impl Notification for Email {
24+
fn send(&self) {
25+
println!("Sending email notification to {}", self.address);
26+
}
27+
}
28+
29+
impl Notification for Sms {
30+
fn send(&self) {
31+
println!("Sending sms notification to {}", self.phone_number);
32+
}
33+
}
34+
35+
fn main() {
36+
let email = Email { address: "example@mail.com".to_string() };
37+
let sms = Sms { phone_number: "1-800-555-0100".to_string() };
38+
39+
let notifications: Vec<Box<dyn Notification>> = vec![Box::new(email), Box::new(sms)];
40+
41+
for notification in notifications {
42+
notification.send();
43+
}
44+
}
45+
```
46+
47+
[`Box<T>`]: https://doc.rust-lang.org/std/boxed/struct.Box.html
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
## Return borrowed or owned text with `Cow`
2+
[![std-badge]][std] [![cat-rust-patterns-badge]][cat-rust-patterns]
3+
4+
Uses [`borrow::Cow`] to avoid allocating when the input string already has the desired form. The function returns [`Cow::Borrowed`] for unchanged input and [`Cow::Owned`]
5+
only when normalization requires a new [`String`], such as converting uppercase text with [`str::to_lowercase`].
6+
This keeps the fast path allocation-free while still allowing transformed output.
7+
8+
```rust,edition2021
9+
use std::borrow::Cow;
10+
11+
fn normalize(input: &str) -> Cow<'_, str> {
12+
if input.chars().any(|c| c.is_uppercase()) {
13+
Cow::Owned(input.to_lowercase())
14+
} else {
15+
Cow::Borrowed(input)
16+
}
17+
}
18+
19+
fn main() {
20+
let owned = normalize("Changes are REQUIRED, this will be Cow::Owned");
21+
let borrowed = normalize("no changes required, this will be cow::borrowed");
22+
23+
assert!(matches!(owned, Cow::Owned(_)));
24+
assert!(matches!(borrowed, Cow::Borrowed(_)));
25+
26+
println!("{}", owned);
27+
println!("{}", borrowed);
28+
}
29+
```
30+
[`str::to_lowercase`]: https://doc.rust-lang.org/std/primitive.str.html#method.to_lowercase
31+
[`borrow::Cow`]: https://doc.rust-lang.org/std/borrow/enum.Cow.html
32+
[`Cow::Borrowed`]: https://doc.rust-lang.org/std/borrow/enum.Cow.html#variant.Borrowed
33+
[`Cow::Owned`]: https://doc.rust-lang.org/std/borrow/enum.Cow.html#variant.Owned
34+
[`String`]: https://doc.rust-lang.org/std/string/struct.String.html
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
## Share mutable structure between owners with `Rc` and `RefCell`
2+
[![std-badge]][std] [![cat-rust-patterns-badge]][cat-rust-patterns]
3+
4+
Uses [`Rc<T>`] to share ownership of one task between multiple dependents and [`RefCell<T>`] to mutate that shared task through [`RefCell::try_borrow_mut`].
5+
The example updates one shared task and reads the result through each dependent using [`RefCell::borrow`].
6+
7+
This pattern is useful when several parts of a single-threaded program need access to the same owned value, but mutations have borrows checked through `RefCell`.
8+
9+
```rust,edition2021
10+
use std::cell::{BorrowMutError, RefCell};
11+
use std::rc::Rc;
12+
13+
#[derive(Debug)]
14+
struct Task {
15+
name: String,
16+
done: bool,
17+
dependencies: Vec<Rc<RefCell<Task>>>,
18+
}
19+
20+
fn new_task(name: &str) -> Rc<RefCell<Task>> {
21+
Rc::new(RefCell::new(Task {
22+
name: name.to_owned(),
23+
done: false,
24+
dependencies: Vec::new(),
25+
}))
26+
}
27+
28+
fn main() -> Result<(), BorrowMutError> {
29+
let generate_api_contract = new_task("Generate API contract");
30+
let implement_endpoint_1 = new_task("Implement endpoint 1 from API contract");
31+
let implement_endpoint_2 = new_task("Implement endpoint 2 from API contract");
32+
33+
{
34+
let mut borrowed_task_1 = implement_endpoint_1.try_borrow_mut()?;
35+
borrowed_task_1.dependencies.push(Rc::clone(&generate_api_contract));
36+
37+
let mut borrowed_task_2 = implement_endpoint_2.try_borrow_mut()?;
38+
borrowed_task_2.dependencies.push(Rc::clone(&generate_api_contract));
39+
40+
generate_api_contract.borrow_mut().done = true;
41+
}
42+
43+
assert!(implement_endpoint_1.borrow().dependencies[0].borrow().done);
44+
assert!(implement_endpoint_2.borrow().dependencies[0].borrow().done);
45+
46+
println!("{:?}", implement_endpoint_1.borrow().dependencies);
47+
println!("{:?}", implement_endpoint_2.borrow().dependencies);
48+
Ok(())
49+
}
50+
```
51+
52+
[`Rc<T>`]: https://doc.rust-lang.org/std/rc/struct.Rc.html
53+
[`RefCell<T>`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html
54+
[`RefCell::try_borrow_mut`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.try_borrow_mut
55+
[`RefCell::borrow`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.borrow
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
## Update text using `swap`, `take`, and `replace`
2+
3+
[![std-badge]][std] [![cat-rust-patterns-badge]][cat-rust-patterns]
4+
5+
Uses [`mem::swap`], [`mem::take`], and [`mem::replace`] to move owned String values between document fields without cloning.
6+
[`mem::swap`] exchanges the drafts of two documents, [`mem::take`] moves a draft out for publishing while leaving an empty String behind,
7+
and [`mem::replace`] installs the new published text while returning the previous version.
8+
9+
```rust,edition2021
10+
use std::mem::{replace, swap, take};
11+
12+
struct Document {
13+
name: &'static str,
14+
draft: String,
15+
published: String,
16+
}
17+
18+
impl Document {
19+
fn publish(&mut self) -> String {
20+
let next_version = take(&mut self.draft);
21+
replace(&mut self.published, next_version)
22+
}
23+
}
24+
25+
fn main() {
26+
let mut guide = Document {
27+
name: "Guide",
28+
draft: "Guide Version 2".to_string(),
29+
published: "Guide Version 1".to_string(),
30+
};
31+
32+
let mut release_notes = Document {
33+
name: "Release notes",
34+
draft: "Release notes for version 2".to_string(),
35+
published: "Release notes for version 1".to_string(),
36+
};
37+
38+
swap(&mut guide.draft, &mut release_notes.draft);
39+
40+
println!("Swapped:");
41+
println!("{} draft: {}", guide.name, guide.draft);
42+
println!("{} draft: {}", release_notes.name, release_notes.draft);
43+
44+
let previous_version = guide.publish();
45+
46+
assert!(guide.draft.is_empty());
47+
assert_eq!(guide.published, "Release notes for version 2");
48+
assert_eq!(previous_version, "Guide Version 1");
49+
}
50+
```
51+
52+
[`mem::swap`]: https://doc.rust-lang.org/std/mem/fn.swap.html
53+
[`mem::replace`]: https://doc.rust-lang.org/std/mem/fn.replace.html
54+
[`mem::take`]: https://doc.rust-lang.org/std/mem/fn.take.html
55+

0 commit comments

Comments
 (0)