Skip to content

Commit d4ea311

Browse files
authored
Idiomatic: Rework Option-in-Drop example to emphasize move semantics (#3168)
Rework the example in the "Drop: Option" slide to emphasize how `Option` is used to achieve move operations in `Drop` code. The current version of the slide emphasizes the wrong thing in my opinion, and fails to actually demonstrate the pattern of needing to perform a move operation in `drop`. I've modified `Handle` to have a `fn close(self)` instead of a `Drop` impl, that way `File::drop` needs to move out of its inner field in order to call `close`.
1 parent 2d930f2 commit d4ea311

1 file changed

Lines changed: 14 additions & 22 deletions

File tree

src/idiomatic/leveraging-the-type-system/raii/drop_option.md

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,55 +21,47 @@ impl File {
2121
}
2222
2323
fn write(&mut self, data: &str) -> std::io::Result<()> {
24+
// We have to go through the `Option` to get the `Handle`
25+
// before we can use it.
2426
let handle = self.0.as_ref().unwrap();
2527
println!("write '{data}' to file '{}'", handle.path);
2628
Ok(())
2729
}
28-
29-
fn close(mut self) -> std::io::Result<&'static str> {
30-
Ok(self.0.take().unwrap().path)
31-
}
3230
}
3331
3432
impl Drop for File {
3533
fn drop(&mut self) {
36-
if let Some(handle) = self.0.take() {
37-
println!("automatically closing handle for file: {}", handle.path);
38-
}
34+
let handle = self.0.take().unwrap();
35+
handle.close();
3936
}
4037
}
4138
4239
struct Handle {
4340
path: &'static str,
4441
}
45-
impl Drop for Handle {
46-
fn drop(&mut self) {
47-
println!("closed handle for file: {}", self.path)
42+
43+
impl Handle {
44+
fn close(self) {
45+
println!("Closing {}", self.path);
4846
}
4947
}
5048
5149
fn main() -> std::io::Result<()> {
5250
let mut file = File::open("foo.txt")?;
5351
file.write("hello")?;
54-
println!("manually closed file: {}", file.close()?);
5552
Ok(())
5653
}
5754
```
5855

5956
<details>
6057

61-
- In this example we want to let the user call `close()` manually so that errors
62-
from closing the file can be reported explicitly.
63-
64-
- At the same time we still want RAII semantics: if the user forgets to call
65-
`close()`, the handle must be cleaned up automatically in `Drop`.
66-
67-
- Wrapping the handle in an `Option` gives us both behaviors. `close()` extracts
68-
the handle with `take()`, and `Drop` only runs cleanup if a handle is still
69-
present.
58+
- In this example we want to call `close` on the inner `Handle` in our `Drop`
59+
impl, but `close` requires ownership of the `Handle`. We can't do this
60+
normally, because we don't get ownership of the `File` object in `drop`, and
61+
therefore can't move out of the field.
7062

71-
Demo: remove the `.close()` call and run the code — `Drop` now prints the
72-
automatic cleanup.
63+
- Wrapping the handle in an `Option` gives us a way to move out of the field
64+
through a mutable reference.
7365

7466
- The main downside is ergonomics. `Option` forces us to handle both the `Some`
7567
and `None` case even in places where, logically, `None` cannot occur. Rust’s

0 commit comments

Comments
 (0)