@@ -479,7 +479,7 @@ of `borrow` and `borrow_mut` methods, it has `get` and `set` methods:
479
479
``` rust
480
480
use std :: cell :: Cell ;
481
481
482
- let mut five = Cell :: new (5 );
482
+ let five = Cell :: new (5 );
483
483
484
484
five . set (6 ); // not five any more O_O
485
485
@@ -499,14 +499,61 @@ But what is 'interior mutability' anyway?
499
499
500
500
## The Interior Mutability Pattern
501
501
502
- The Interior Mutability Pattern is super unsafe internally but safe to use
503
- from the outside and is totally safe, totally, trust us, seriously, it's safe.
502
+ * Interior mutability* is a design pattern in Rust for allowing you to mutate
503
+ something that's immutable. Wait, what? Let's compare these two pieces of code.
504
+ What's different about them?
504
505
505
- Allude to ` UnsafeCell<T> ` maybe. Affects optimizations since &mut T is unique.
506
- UnsafeCell turns off those optimizations so that everything doesn't break.
506
+ ``` rust
507
+ use std :: cell :: Cell ;
508
+
509
+ // one
510
+ let mut five = 5 ;
511
+
512
+ five = 6 ;
513
+
514
+ // two
515
+ let five = Cell :: new (5 );
516
+
517
+ five . set (6 );
518
+ ```
519
+
520
+ There are three things that are different:
521
+
522
+ 1 . We use ` 5 ` in sample one, but ` Cell::new(5) ` in sample two.
523
+ 2 . We use ` = ` in sample one, but ` set ` in sample two.
524
+ 3 . ` five ` is mutable in sample one, but not in sample two.
525
+
526
+ That third difference? That's interior mutability.
527
+
528
+ Why are we allowed to do this? Well, to some degree, we're not. The reason we
529
+ call interior mutability a "pattern" is that it's not really a language
530
+ feature, it's a design pattern for libraries. More specifically, it's a pattern
531
+ that uses ` unsafe ` code inside to bend Rust's usual rules. We haven't yet covered
532
+ unsafe code in-depth, we will in Chapter 20. Luckily for us, you don't have to
533
+ understand how it works inside to use it. All you need to know is that the
534
+ various family of ` Cell ` types, as well as some others like ` Mutex<T> ` (that we'll
535
+ cover in the next chapter, on concurrency) follow this pattern.
536
+
537
+ Why is this useful? Well, remember when we said that ` Rc<T> ` has to store
538
+ immutable data? Given that ` RefCell<T> ` is immutable, but has interior mutability,
539
+ we can combine ` Rc<T> ` and ` RefCell<T> ` to get a type that's both reference
540
+ counted and mutable. Like this:
541
+
542
+ ``` rust
543
+ use std :: rc :: Rc ;
544
+ use std :: cell :: RefCell ;
545
+
546
+ let five = Rc :: new (RefCell :: new (5 ));
547
+
548
+ let other_rc = five . clone ();
549
+
550
+ * other_rc . borrow_mut () = 6 ;
551
+ ```
507
552
508
- This is how you can opt-out of the default of Rust's ownership rules and opt
509
- in to different guarantees.
553
+ This is where interior mutability is useful: when you have something that
554
+ requires immutability, but you also need to mutate something. This comes up
555
+ with types like ` Rc<T> ` , but it can also come up in concurrency situations. In
556
+ general, it's a fairly rare thing to need, but when you need it, it does exist.
510
557
511
558
### Cycles
512
559
@@ -515,37 +562,92 @@ is deallocated. But what about this program?
515
562
516
563
``` rust
517
564
use std :: rc :: Rc ;
565
+ use std :: cell :: RefCell ;
518
566
519
567
struct Cycle {
520
- really_bad : Option <Rc <Cycle >>,
568
+ really_bad : RefCell < Option <Rc <Cycle > >>,
521
569
leaked_data : i32 ,
522
570
}
523
571
524
572
fn main () {
525
573
let mut oh_no = Rc :: new (Cycle {
526
- really_bad : None ,
574
+ really_bad : RefCell :: new ( None ) ,
527
575
leaked_data : 5 ,
528
576
});
529
577
530
- let clone = oh_no . clone ();
578
+ let clone = oh_no . clone ();
531
579
532
- oh_no . really_bad = Some (clone );
580
+ * oh_no . really_bad. borrow_mut () = Some (clone );
533
581
}
534
582
```
535
583
584
+ There's a lot going on here. Fundamentally, ` Cycle ` is a type that contains an
585
+ ` Rc<Cycle> ` . This means that we can have a 'referene cycle', hence the name of
586
+ the struct. Here, we've constructed one in ` main ` : we have ` oh_no ` , and then we
587
+ create a clone of it, ` clone ` . Since we've made a clone of it, the reference
588
+ count is two: one for the initial ` Rc<T> ` , and one for the clone. When ` oh_no `
589
+ goes out of scope at the end of ` main ` , it will decrement the count to one. But
590
+ that's it: ` clone ` never really goes out of scope, since it was moved into
591
+ ` oh_no ` . This means that this memory is now unreachable, yet will never be
592
+ cleaned up. It'll just sit there with a count of one, forever. In this
593
+ specific case, the program ends right away, so it's not a problem, but in a
594
+ more complex program, it would be.
595
+
596
+ Now, as you can see, doing this is very hard. To be honest, your authors had to
597
+ look up previous discussions of an example to get this right. But it can
598
+ happen, and the way that it happens is reasonably obvious: If you have an
599
+ ` Rc<T> ` that contains an ` Rc<T> ` , beware.
600
+
536
601
#### Solution: turn an Rc into a ` Weak<T> `
537
602
538
- Same as Rc, but doesn't count towards the strong ref count. When you do this, the
539
- strong ref count goes down and the weak count goes up.
603
+ To help with this problem, the Rust standard library contains a different
604
+ type: ` Weak<T> ` . Let's see what that looks like:
605
+
606
+ ``` rust
607
+ use std :: rc :: {Rc , Weak };
608
+ use std :: cell :: RefCell ;
609
+
610
+ struct Cycle {
611
+ really_bad : RefCell <Option <Weak <Cycle >>>,
612
+ leaked_data : i32 ,
613
+ }
614
+
615
+ fn main () {
616
+ let mut oh_no = Rc :: new (Cycle {
617
+ really_bad : RefCell :: new (None ),
618
+ leaked_data : 5 ,
619
+ });
620
+
621
+ let clone = Rc :: downgrade (& oh_no . clone ());
622
+
623
+ * oh_no . really_bad. borrow_mut () = Some (clone );
624
+ }
625
+ ```
626
+
627
+ ` Weak<T> ` is exactly like ` Rc<T> ` , except that its reference count doesn't, well,
628
+ count when determining if something should be freed. You can turn an ` Rc<T> ` into
629
+ a ` Weak<T> ` with the ` Rc::downgrade ` associated method, which takes an ` &Rc<T> `
630
+ as an argument, and gives a ` Weak<T> ` back.
540
631
541
- Data gets cleaned up when the strong count is 0, no matter what the weak count is.
632
+ So in this example, when we call ` oh_no.clone() ` , we increment the count to two.
633
+ But when we pass that clone to ` downgrade ` , that count goes down again, to one.
634
+ Now, at the end of the function, when ` oh_no ` goes out of scope, it reduces the
635
+ count from one to zero, and the memory is freed. Success! We've broken the cycle.
542
636
543
- Why is the weak count needed then????
637
+ If you're doing complex things with ` Rc<T> ` s, you should investigate if you
638
+ have a cycle, and insert a ` Weak<T> ` so that your memory doesn't leak. The
639
+ specifics depend on exactly what you're doing, but luckily, this isn't a
640
+ Rust-specific idea; all of this translates over to other reference counting
641
+ libraries in other languages, so doing some reading about it should help you.
544
642
545
643
546
644
## Summary
547
645
548
- If you want to implement your own smart pointer, go read the Nomicon.
646
+ Whew! Smart pointers are powerful, but complex. We've covered the basics of
647
+ smart pointers, and how to use some of the most common smart pointers.
648
+ Implementing your own smart pointers is out of the scope of this book; you
649
+ should check out the Nomicon if you're interested in building these kinds of
650
+ abstractions.
549
651
550
- Now let's talk about concurrency, and some smart pointers that can be used
551
- with multiple threads .
652
+ Next, let's talk about concurrency in Rust. We'll even learn aobut a few new
653
+ smart pointers that can help us with it .
0 commit comments