<style> /* basic design */ .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6, .reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p { font-family: 'Meiryo UI', 'Source Sans Pro', Helvetica, sans-serif, 'Helvetica Neue', 'Helvetica', 'Arial', 'Hiragino Sans', 'ヒラギノ角ゴシック', YuGothic, 'Yu Gothic'; text-align: left; line-height: 1.5; letter-spacing: normal; text-shadow: none; word-wrap: break-word; color: #AAA; } .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 {font-weight: bold;} .reveal h1, .reveal h2, .reveal h3 {color: #2980b9;} .reveal th {background: #DDD;} .reveal section img {background:none; border:none; box-shadow:none; max-width: 95%; max-height: 95%;} .reveal blockquote {width: 90%; padding: 0.5vw 3.0vw;} .reveal table {margin: 1.0vw auto;} .reveal code {line-height: 1.2;} .reveal p, .reveal li {padding: 0vw; margin: 0vw;} .reveal .box {margin: -0.5vw 1.5vw 2.0vw -1.5vw; padding: 0.5vw 1.5vw 0.5vw 1.5vw; background: #EEE; border-radius: 1.5vw;} /* table design */ .reveal table {background: #f5f5f5;} .reveal th {background: #444; color: #fff;} .reveal td {position: relative; transition: all 300ms;} .reveal tbody:hover td { color: transparent; text-shadow: 0 0 3px #AAA;} .reveal tbody:hover tr:hover td {color: #444; text-shadow: 0 1px 0 #CCC;} /* blockquote design */ .reveal blockquote { width: 90%; padding: 0.5vw 0 0.5vw 6.0vw; font-style: italic; background: #f5f5f5; } .reveal blockquote:before{ position: absolute; top: 0.1vw; left: 1vw; content: "\f10d"; font-family: FontAwesome; color: #2980b9; font-size: 3.0vw; } /* font size */ .reveal h1 {font-size: 4.0vw;} .reveal h2 {font-size: 3.5vw;} .reveal h3 {font-size: 2.8vw;} .reveal h4 {font-size: 2.6vw;} .reveal h5 {font-size: 2.4vw;} .reveal h6 {font-size: 2.2vw;} .reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p {font-size: 2.0vw;} .reveal code {font-size: 1.0vw;} /* new color */ .red {color: #EE6557;} .blue {color: #16A6B6;} /* split slide */ #right {left: -18.33%; text-align: left; float: left; width: 50%; z-index: -10;} #left {left: 31.25%; text-align: left; float: left; width: 50%; z-index: -10;} </style> <style> /* specific design */ .reveal h2 { padding: 0 1.5vw; margin: 0.0vw 0 2.0vw -2.0vw; border-left: solid 1.0vw #2980b9; border-bottom: solid 0.6vw #d7d7d7; } </style> <!-- --------------------------------------------------------------------------------------- --> # Rust Study Session \#15 ## Ch.15 (part 1) - Smart Pointers ### 2020.11.13 - Salvatore La Bua --- ## Summary - What is a pointer. - Using __Box\<T\>__ to point to data on the heap. - Smart Pointers as regular references. - Running code on cleanup. - __Rc\<T\>__, the Reference Counted smart pointer. --- ## Pointers ### What is a pointer - In general, a pointer is a variable that contains an address in memory. - Such address refers to some other data. --- ### Reference - Most common type of pointer is the __reference__. - Indicated by __&__, only borrows the value it points to. - References are simple pointers. - There is no overhead. --- ### Smart Pointers - Data structures with additional metadata capabilities. - Can own the data they point to. - Originated in C++, also available in other languages. --- ### Smart Pointers - __String__ - __Vec\<T\>__ - __Reference Counting__ smart pointer type: - Keeps track of data owners. - Clean up when no more owners remain. --- ### Smart Pointers - Usually implemented as Structs. - Implement the Deref and Drop traits: - __Deref__: to behave as a Reference. - __Drop__: behaviour when getting out of scope. --- ### Smart Pointers - __Box\<T\>__ for allocating values on the heap. - __Rc\<T\>__ to enable multiple ownership. - (Ref\<T\> and RefMut\<T\>, accessed through RefCell\<T\>) - (Interior mutability and reference cycles) --- ## Using __Box\<T\>__ to point to data - Only the pointer is stored on the stack. - The data is stored on the heap. - No performance overhead. --- ### __Box\<T\>__ to point data #### Use when: - A type size is not know at compile time. - Transfer ownership of a large amount of data without copying the data itself. - To own a value for which its type implements a particular trait. --- ### __Box\<T\>__ to store data ```rust= fn main() { // Box points to 5 allocated on the heap let b = Box::new(5); println!("b = {}", b); } ``` --- ### __Box\<T\>__ #### Enabling recursive types - The size of a recursive type can not be known at compile time. - Boxes have a known size, therefore they can be used in recursive types. --- ### Cons List #### Example ```rust= enum List { Cons(i32, List), Nil, } ``` Equivalent to ```rust= use crate::List::{Cons, Nil}; fn main() { let list = Cons(1, Cons(2, Cons(3, Nil))); } ``` --- ### Cons List ![](https://doc.rust-lang.org/book/img/trpl15-01.svg) --- ### Cons List #### Compilation of recursive types ```bash= $ cargo run Compiling cons-list v0.1.0 (file:///projects/cons-list) error[E0072]: recursive type `List` has infinite size --> src/main.rs:1:1 | 1 | enum List { | ^^^^^^^^^ recursive type has infinite size 2 | Cons(i32, List), | ---- recursive without indirection | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `List` representable error[E0391]: cycle detected when processing `List` --> src/main.rs:1:1 | 1 | enum List { | ^^^^^^^^^ | = note : ...which again requires processing `List`, completing the cycle = note : cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, value: List } }` error: aborting due to 2 previous errors Some errors have detailed explanations: E0072, E0391. For more information about an error, try `rustc --explain E0072`. error: could not compile `cons-list`. To learn more, run the command again with --verbose. ``` --- ### Cons List (using Box\<T\>) ```rust= enum List { Cons(i32, Box<List>), Nil, } use crate::List::{Cons, Nil}; fn main() { let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil)))))); } ``` --- ### Cons List (using Box\<T\>) ![](https://doc.rust-lang.org/book/img/trpl15-02.svg) <div style="text-align: right">□</div> --- ## Smart Pointers as a Reference ### The Deref trait Customise the behaviour of the *deference operator* __*__ --- ### Regular references ```rust= fn main() { let x = 5; let y = &x; assert_eq!(5, x); assert_eq!(5, *y); // using the deference operator } ``` --- ### Box\<T\> as a reference ```rust= fn main() { let x = 5; let y = Box::new(x); assert_eq!(5, x); assert_eq!(5, *y); // using the deference operator } ``` --- ### Using a custom smart pointer ```rust= struct MyBox<T>(T); impl<T> MyBox<T> { fn new(x: T) -> MyBox<T> { MyBox(x) } } ``` ```rust= fn main() { let x = 5; let y = MyBox::new(x); assert_eq!(5, x); assert_eq!(5, *y); } ``` --- ### Using a custom smart pointer ```bash= $ cargo run Compiling deref-example v0.1.0 (file:///projects/deref-example) error[E0614]: type `MyBox<{integer}>` cannot be dereferenced --> src/main.rs:14:19 | 14 | assert_eq!(5, *y); | ^^ error: aborting due to previous error For more information about this error, try `rustc --explain E0614`. error: could not compile `deref-example`. To learn more, run the command again with --verbose. ``` --- ### Using a custom smart pointer #### Implementing the Deref trait ```rust= use std::ops::Deref; impl<T> Deref for MyBox<T> { type Target = T; fn deref(&self) -> &T { &self.0 } } ``` --- ### Deref coercion Converts a type that implement the deref trait into a reference to another type. #### Example ```rust= fn hello(name: &str) { println!("Hello, {}!", name); } ``` ```rust= fn main() { let m = MyBox::new(String::from("Rust")); hello(&m); } ``` --- ### Defer coercion and mutability Use the __DerefMut__ trait to override the * operator on mutable references. - From &T to &U when T: Deref\<Target=U\> - From &mut T to &mut U when T: DerefMut\<Target=U\> - From &mut T to &U when T: Deref\<Target=U\> <div style="text-align: right">□</div> --- ## Running code on cleanup ### The Drop trait ```rust= struct CustomSmartPointer { data: String, } impl Drop for CustomSmartPointer { fn drop(&mut self) { println!("Dropping CustomSmartPointer with data `{}`!", self.data); } } ``` --- ### The Drop trait ```rust= fn main() { let c = CustomSmartPointer { data: String::from("my stuff"), }; let d = CustomSmartPointer { data: String::from("other stuff"), }; println!("CustomSmartPointers created."); } ``` ```bash= $ cargo run Compiling drop-example v0.1.0 (file:///projects/drop-example) Finished dev [unoptimized + debuginfo] target(s) in 0.60s Running `target/debug/drop-example` CustomSmartPointers created. Dropping CustomSmartPointer with data `other stuff`! Dropping CustomSmartPointer with data `my stuff`! ``` --- ### Dropping a value early ```rust= fn main() { let c = CustomSmartPointer { data: String::from("some data"), }; println!("CustomSmartPointer created."); c.drop(); println!("CustomSmartPointer dropped before the end of main."); } ``` ```bash= $ cargo run Compiling drop-example v0.1.0 (file:///projects/drop-example) error[E0040]: explicit use of destructor method --> src/main.rs:16:7 | 16 | c.drop(); | ^^^^ explicit destructor calls not allowed error: aborting due to previous error ``` --- ### Dropping a value early (fix) ```rust= fn main() { let c = CustomSmartPointer { data: String::from("some data"), }; println!("CustomSmartPointer created."); drop(c); // std::mem::drop println!("CustomSmartPointer dropped before the end of main."); } ``` ```bash= $ cargo run Compiling drop-example v0.1.0 (file:///projects/drop-example) Finished dev [unoptimized + debuginfo] target(s) in 0.73s Running `target/debug/drop-example` CustomSmartPointer created. Dropping CustomSmartPointer with data `some data`! CustomSmartPointer dropped before the end of main. ``` <div style="text-align: right">□</div> --- ## Rc\<T\>, the Reference Counted smart pointer A single value might have multiple owners. --- ### Implement a graph ```rust= use crate::List::{Cons, Nil}; fn main() { let a = Cons(5, Box::new(Cons(10, Box::new(Nil)))); let b = Cons(3, Box::new(a)); let c = Cons(4, Box::new(a)); } ``` ![](https://doc.rust-lang.org/book/img/trpl15-03.svg) --- ### Implement a graph ```bash= $ cargo run Compiling cons-list v0.1.0 (file:///projects/cons-list) error[E0382]: use of moved value: `a` --> src/main.rs:11:30 | 9 | let a = Cons(5, Box::new(Cons(10, Box::new(Nil)))); | - move occurs because `a` has type `List`, which does not implement the `Copy` trait 10 | let b = Cons(3, Box::new(a)); | - value moved here 11 | let c = Cons(4, Box::new(a)); | ^ value used here after move error: aborting due to previous error For more information about this error, try `rustc --explain E0382`. error: could not compile `cons-list`. To learn more, run the command again with --verbose. ``` --- ### Implement a graph (fix) ```rust= enum List { Cons(i32, Rc<List>), Nil, } use crate::List::{Cons, Nil}; use std::rc::Rc; fn main() { let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil))))); let b = Cons(3, Rc::clone(&a)); let c = Cons(4, Rc::clone(&a)); } ``` --- ### Implement a graph (rc check) ```rust= fn main() { let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil))))); println!("count after creating a = {}", Rc::strong_count(&a)); let b = Cons(3, Rc::clone(&a)); println!("count after creating b = {}", Rc::strong_count(&a)); { let c = Cons(4, Rc::clone(&a)); println!("count after creating c = {}", Rc::strong_count(&a)); } println!("count after c goes out of scope = {}", Rc::strong_count(&a)); } ``` --- ### Implement a graph (rc check) ```bash= $ cargo run Compiling cons-list v0.1.0 (file:///projects/cons-list) Finished dev [unoptimized + debuginfo] target(s) in 0.45s Running `target/debug/cons-list` count after creating a = 1 count after creating b = 2 count after creating c = 3 count after c goes out of scope = 2 ``` <div style="text-align: right">□</div> --- ## References From __The Rust Programming Language__ book: - Ch. 15: Smart Pointers [[EN]](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html) [[JP]](https://doc.rust-jp.rs/book-ja/ch15-00-smart-pointers.html) ---
{"metaMigratedAt":"2023-06-15T15:32:30.217Z","metaMigratedFrom":"YAML","title":"Rust Ch.15 (part 1) - Smart Pointers","breaks":true,"description":"Rust Ch.15 (part 1) - Smart Pointers","slideOptions":"{\"theme\":\"black\",\"slideNumber\":\"c/t\",\"center\":false,\"transition\":\"fade\",\"keyboard\":true}","contributors":"[{\"id\":\"c5f0d40d-be35-4660-a8b4-7736feeb9327\",\"add\":27222,\"del\":13937}]"}
    600 views