Skip to content

Commit 6ce558c

Browse files
committed
switch example to hash set, it's cleaner
1 parent 0e0a711 commit 6ce558c

File tree

5 files changed

+28
-27
lines changed

5 files changed

+28
-27
lines changed
Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
11
#![allow(dead_code)]
22
fn main() {}
33

4-
use std::cell::Cell;
4+
use std::{collections::HashSet, iter::FromIterator};
55

6-
fn cell_shortener<'a, 'b>(s: &'a Cell<&'static str>) -> &'a Cell<&'b str> {
6+
fn hash_set_shortener<'a, 'b>(s: &'a mut HashSet<&'static str>) -> &'a mut HashSet<&'b str> {
77
s
88
}
99

1010
// ANCHOR: all
11-
fn cell_counterexample() {
12-
let foo: Cell<&'static str> = Cell::new("foo");
11+
fn hash_set_counterexample() {
12+
let mut foo: HashSet<&'static str> = HashSet::from_iter(["static"]);
1313
let owned_string: String = "non_static".to_owned();
1414

15-
// If we pretend that cell_shortener works
16-
let shorter_foo = cell_shortener(&foo);
15+
// If we pretend that hash_set_shortener works
16+
let shorter_foo = hash_set_shortener(&mut foo);
1717

1818
// then `shorter_foo` and `foo` would be aliases of each other, which would
19-
// mean that you could use `shorter_foo` to replace `foo`s `Cell` with a
20-
// non-static string:
19+
// mean that you could use `shorter_foo` to insert a non-static string:
2120
shorter_foo.replace(&owned_string);
2221

2322
// Now `foo`, which is an alias of `shorter_foo`, has a non-static string
2423
// in it! Whoops.
2524
}
26-
// ANCHOR_END: all
25+
// ANCHOR_END: all
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
#![allow(dead_code)]
22
fn main() {}
33

4-
use std::cell::Cell;
4+
use std::collections::HashSet;
55

66
// ANCHOR: all
7-
fn cell_lengthener<'a, 'b>(s: &'a Cell<&'b str>) -> &'a Cell<&'static str> {
7+
fn hash_set_lengthener<'a, 'b>(s: &'a mut HashSet<&'b str>) -> &'a mut HashSet<&'static str> {
88
s
99
}
1010

11-
// ANCHOR_END: all
11+
// ANCHOR_END: all
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
#![allow(dead_code)]
22
fn main() {}
33

4-
use std::cell::Cell;
4+
use std::collections::HashSet;
55

66
// ANCHOR: all
7-
fn cell_shortener<'a, 'b>(s: &'a Cell<&'static str>) -> &'a Cell<&'b str> {
7+
fn hash_set_shortener<'a, 'b>(s: &'a mut HashSet<&'static str>) -> &'a mut HashSet<&'b str> {
88
s
99
}
1010

11-
// ANCHOR_END: all
11+
// ANCHOR_END: all

src/ch01-01-building-an-intuition.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@ its lifetime shorter:
66
{{#rustdoc_include ../code/ch01-01-building-an-intuition/lifetime-shortener/src/main.rs:all}}
77
```
88

9+
<!-- Note: all the code sample names begin with "cell" rather than "hash-set" as you might expect. This is because hash sets should -->
10+
911
Intuitively, this feels like it should compile: if a string lasts for the whole
1012
process it should also last for any part of it. And it does!
1113

12-
Now let's make it slightly more complicated. Let's introduce a `Cell` into the
13-
picture. As a reminder, a `Cell` allows for the data inside it to be changed.
14+
Now let's make it slightly more complicated. Let's put some strings into a `HashSet`.
1415
```rust,does_not_compile
1516
{{#rustdoc_include ../code/ch01-01-building-an-intuition/cell-shortener/src/main.rs:all}}
1617
```
1718

18-
`cell_shortener` doesn't compile :( Can you tell why? Think about it for a minute,
19+
`hash_set_shortener` doesn't compile :( Can you tell why? Think about it for a minute,
1920
try using your intuition...
2021
```rust,does_not_compile
2122
{{#rustdoc_include ../code/ch01-01-building-an-intuition/cell-example/src/main.rs:all}}
@@ -25,16 +26,16 @@ try using your intuition...
2526
{{#rustdoc_include ../code/ch01-01-building-an-intuition/cell-counterexample/src/main.rs:all}}
2627
```
2728

28-
It isn't just `Cell` which is problematic in this way. `RefCell`, `OnceCell`,
29-
`Mutex`, `&mut` references -- anything "inside" some sort of mutable context has
30-
this issue.
29+
It isn't just `&mut` which is problematic in this way. This also occurs with any sort of interior
30+
mutability, like `RefCell`, `OnceCell`, or `Mutex` -- anything inside some sort of mutable context
31+
has this issue.
3132

3233
Now, what about a hypothetical "lengthener" function?
3334
```rust,does_not_compile
3435
{{#rustdoc_include ../code/ch01-01-building-an-intuition/lifetime-lengthener/src/main.rs:all}}
3536
```
3637

37-
This is obviously bogus, right? You can't just turn an arbitrary borrowed string
38+
This is clearly bogus, right? You can't just turn an arbitrary borrowed string
3839
and make it last the duration of the entire process. Similarly:
3940
```rust,does_not_compile
4041
{{#rustdoc_include ../code/ch01-01-building-an-intuition/cell-lengthener/src/main.rs:all}}
@@ -46,5 +47,8 @@ borrowed string.
4647
{{#rustdoc_include ../code/ch01-01-building-an-intuition/fn-ptr-lengthener/src/main.rs:all}}
4748
```
4849

49-
Ahhh, intuitively, this should work. And it does. You can take a callback that
50-
takes an arbitrary borrowed string and turn it into one that takes in a static string.
50+
This feels like should work. You can take a callback that takes an arbitrary borrowed string and
51+
turn it into one that takes in a static string, since you're weakening the guarantee. And it does.
52+
53+
How can we handle these different cases in a principled way? That's where variance comes in. We're
54+
going to talk about this in the next chapter, *[Formalizing variance](ch01-02-formalizing-variance.md)*.

src/ch01-02-formalizing-variance.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# Formalizing variance
22

3-
How can all these intuitions be formalized? It's done through the idea of *variance*.
4-
53
Some kinds of memory live longer than others. This is captured through the idea
64
of the *outlives* relationship. If `'b` outlives `'a`, it is written as `'b: 'a`.
75
For example, in the definition:
@@ -20,7 +18,7 @@ For a type `T<'a>`, `'a` may be:
2018
* **invariant**, which means that even if `'b: 'a`, nothing can be said about
2119
the relationship between `T<'b>` and `T<'a>`. This can happen for one of two reasons:
2220
* If the lifetime is present "inside" some sort of mutable context -- whether
23-
a `&mut` reference, or interior mutability like `Cell`/`RefCell`/`Mutex`.
21+
a `&mut` reference, or interior mutability like `RefCell`, `OnceCell`, or`Mutex`.
2422

2523
* If the lifetime is used in multiple spots where the variances conflict.
2624
See [Conflicts and type parameters](./ch01-03-conflicts-and-type-parameters.md) for

0 commit comments

Comments
 (0)