Skip to content
This repository has been archived by the owner on Dec 4, 2022. It is now read-only.

Latest commit

 

History

History
593 lines (431 loc) · 15.2 KB

index.md

File metadata and controls

593 lines (431 loc) · 15.2 KB

LEARN RUST VERBS

https://sharils.github.io/slides/20220731-learn-rust-verbs

sharils.github.io/slides/20220731-learn-rust-verbs


Q&A

Join Slido: Enter #code to vote and ask questions

app.sli.do/event/pdmHAZWcGDERsxZzcx6i7g


THE PROBLEM

fn main() {
    let bad_beef = 0xBadBeef;
    println!("No {:#x}", bad_beef);
}

Easy. ▶️


THE PROBLEM

fn inspect(bad_beef: i32) -> i32 {
    dbg!(bad_beef);
    return bad_beef;
}

fn main() {
    let bad_beef = 0xBadBeef;
    println!("No {:#x}", inspect(bad_beef));
}

Let's inspect. ▶️


THE PROBLEM

fn inspect(bad_beef: String) -> String {
    dbg!(bad_beef);
    return bad_beef;
}

fn main() {
    let bad_beef = String::from("Bad Beef!");
    println!("No {}", inspect(bad_beef));
}

Now a String. ▶️


THE PROBLEM

   Compiling playground v0.0.1 (/playground)
error[E0382]: use of moved value: `bad_beef`
 --> src/main.rs:3:12
  |
1 | fn inspect(bad_beef: String) -> String {
  |            -------- move occurs because `bad_beef` has
                        type `String`, which does not
                        implement the `Copy` trait
2 |     dbg!(bad_beef);
  |     -------------- value moved here
3 |     return bad_beef;
  |            ^^^^^^^^ value used here after move

For more information about this error, try `rustc --explain E0382`.
error: could not compile `playground` due to previous error

Oops!


COPY

// 3. Copy i32 to bad_beef
fn inspect(bad_beef: i32) -> i32 {
    dbg!(bad_beef); // 4. Copy bad_beef to dbg ✅
    return bad_beef; // 5. Copy bad_beef to main
}

fn main() {
    // 1. Copy i32 to bad_beef
    let bad_beef = 0xBadBeef;

    // 2. Copy bad_beef to inspect
    // 6. Copy bad_beef to println
    println!("No {:#x}", inspect(bad_beef));
}

▶️


COPY

Stack Heap
Access Faster Slower
Allocation Faster Slower
Drop Faster Slower
Jump Less More
Size Known&Fixed Unknown∥Dynamic

The Stack and the Heap


COPY

copy

→ impl Copy

→ Stack-Only Data

→ Known&Fixed Size At Compile Time


MOVE

fn inspect(bad_beef: String) -> String {
    dbg!(bad_beef);
    return bad_beef;
}

fn main() {
    let bad_beef = String::from("Bad Beef!");
    println!("No {}", inspect(bad_beef));
}

Not too early, not too late, not too many, not too few and no GC, i.e.

at the right time, for the right times.


MOVE

// 4. Move String into bad_beef
fn inspect(bad_beef: String) -> String {
    dbg!(bad_beef); // 5. Move bad_beef into dbg
                    // 6. Invalidate bad_beef in inspect
                    // 7. Drop bad_beef at the end of dbg
    return bad_beef; // 8. Move bad_beef into main 💥
}
fn main() {
    // 1. Move String into bad_beef
    let bad_beef = String::from("Bad Beef!");
    // 2. Move bad_beef into inspect
    // 3. Invalidate bad_beef in main
    // 9. Move String into println
    println!("No {}", inspect(bad_beef));
}

Move: change of ownership i.e. right to drop. ▶️


MOVE

           ─┬─ stack ─┬─ Copy ─── copy ─── Duration
            │         │
            │         ├─ Drop ─── move ─── ?
            │         │
            │         └─ None ─── move ─── ?
            │
            └─ heap ──┬─ Drop ─── move ─── Vec
                      │
                      └─ None ─── move ─── String

CLONE

   Compiling playground v0.0.1 (/playground)
error[E0382]: use of moved value: `bad_beef`
 --> src/main.rs:3:12
  |
1 | fn inspect(bad_beef: String) -> String {
  |            -------- move occurs because `bad_beef` has
                        type `String`, which does not
                        implement the `Copy` trait
2 |     dbg!(bad_beef);
  |     -------------- value moved here
3 |     return bad_beef;
  |            ^^^^^^^^ value used here after move

For more information about this error, try `rustc --explain E0382`.
error: could not compile `playground` due to previous error

How about deep copy?


CLONE

fn inspect(bad_beef: String) -> String {
    // 1. Clone bad_beef
    // 2. Move clone of bad_beef into dbg ✅
    dbg!(bad_beef.clone());

    return bad_beef;
}

fn main() {
    let bad_beef = String::from("Bad Beef!");

    println!("No {}", inspect(bad_beef));
}

No free lunch ▶️


BORROW

// 3. Move String into bad_beef
fn inspect(bad_beef: String) -> String {
    dbg!(&bad_beef); // 4. Borrow bad_beef
                     // 5. Copy borrow of bad_beef to dbg ✅
    return bad_beef; // 6. Move bad_beef into main
}
fn main() {
    // 1. Move String into bad_beef
    let bad_beef = String::from("Bad Beef!");

    // 2. Move bad_beef into inspect
    // 7. Move String into println
    println!("No {}", inspect(bad_beef));
}

Borrow: no change of ownership → no right to drop. ▶️


BORROW

// 4. Copy borrow of String to bad_beef
fn inspect(bad_beef: &String) -> &String {
    dbg!(bad_beef);  // 5. Copy borrow of bad_beef to dbg
    return bad_beef; // 6. Copy borrow of bad_beef to main
}
fn main() {
    // 1. Move String into bad_beef
    let bad_beef = String::from("Bad Beef!");

    // 2. Borrow bad_beef
    // 3. Copy borrow of bad_beef to inspect ✅
    // 7. Copy borrow of String to println
    println!("No {}", inspect(&bad_beef));
}

Borrow before inspect. ▶️


BORROW

// 4. Copy borrow of String to bad_beef
fn inspect(bad_beef: &String) -> &String {
    dbg!(bad_beef);  // 5. Copy borrow of String to dbg
    return bad_beef; // 6. Copy borrow of String to main
}
fn main() {
    // 1. Borrow String
    // 2. Copy borrow of String to bad_beef ✅
    let bad_beef = &String::from("Bad Beef!");

    // 3. Copy borrow of String to inspect
    // 7. Copy borrow of String to println
    println!("No {}", inspect(bad_beef));
}

Borrow on initialisation. ▶️


REF

// 3. Copy borrow of String to bad_beef
fn inspect(bad_beef: &String) -> &String {
    dbg!(bad_beef);  // 4. Copy borrow of String to dbg
    return bad_beef; // 5. Copy borrow of String to main
}
fn main() {
    // 1. Move String into bad_beef
    let bad_beef = String::from("Bad Beef!");

    // 2. Move String into inspect 💥
    // 6. Copy borrow of String to println
    println!("No {}", inspect(bad_beef));
}

String ≠ &String ▶️


REF

fn inspect(bad_beef: String) -> String {
    // pub fn clone(&self) -> String ⁉️
    dbg!(bad_beef.clone());

    return bad_beef;
}

fn main() {
    let bad_beef = String::from("Bad Beef!");

    println!("No {}", inspect(bad_beef));
}

automatic referencing and dereferencing! ▶️


REF

fn inspect(bad_beef: &str) -> &str {
    dbg!(bad_beef);
    return bad_beef;
}

fn main() {
    // string literal is a string slice
    let bad_beef = "Bad Beef!";

    println!("No {}", inspect(bad_beef));
}

String literal ▶️


REF

fn inspect(bad_beef: &str) -> &str {
    dbg!(bad_beef);
    return bad_beef;
}

fn main() {
    // a string slice of String
    let bad_beef = &String::from("Bad Beef!")[..];

    println!("No {}", inspect(bad_beef));
}

String slice ▶️


REF

      ref ─┬─ slice ─┬─ String slice ─── string literal
           │         │
           │         ├─ Vec slice
           │         │
           │         └─ ...
           │
           └─ borrow

DEREF

fn emphasise(bad_beef: &mut String) {
    *bad_beef += "?"; // 1. Deref *bad_beef to mut String
                      // 2. Call String’s add_assign
}

fn main() {
    let mut bad_beef = String::from("Bad Beef!");
    
    emphasise(&mut bad_beef);

    println!("No {}", bad_beef);
}

Deref ▶️


DEREF

fn inspect(bad_beef: &str) -> &str {
    dbg!(bad_beef);
    return bad_beef;
}

fn main() {
    let bad_beef = String::from("Bad Beef!");

    // 1. borrow bad_beef as &String
    // 2. deref coerce &String to &str
    // 3. Copy &str to inspect
    println!("No {}", inspect(&bad_beef));
}

Deref coercion ▶️


RefCell

use std::cell::RefCell;

fn emphasise(bad_beef: &RefCell<String>) {
    *bad_beef.borrow_mut() += "?";
}

fn main() {
    let bad_beef = RefCell::new(String::from("Bad Beef!"));
    
    emphasise(&bad_beef);

    println!("No {}", bad_beef.borrow() );
}

interior mutability ▶️


RefCell

&mut RefCell
Borrow Checker Compile Time Runtime
Catch Error Compiler Code Review
Runtime Cost Zero More
Violation Won't compile Runtime Panic
Safe Case Coverage Less More

RC

use std::rc::Rc;
fn inspect(bad_beef: Rc<String>) -> Rc<String> {
    // 1. Clone Rc<String> (shallow copy)
    // 2. Increase strong count
    // 3. Move the clone of Rc into dbg
    // 4. Drop the clone of Rc at the end of dbg
    // 5. Decrease strong count
    dbg!(Rc::clone(&bad_beef));
    return bad_beef;
}
fn main() {
    let bad_beef = Rc::new(String::from("Bad Beef!"));
    println!("No {}", inspect(bad_beef));
}

multiple ownership ▶️


RC

No Rc Use Rc
Catch Error Compiler Code Review
Runtime Cost Zero More
Violation Won't Compile Memory Leak
Circular Reference Improbable Possible

Use Weak (as in weak reference) to fix circular reference memory leak.


CONCLUSION

Try to say those verbs (copy, move, clone, borrow, ref, deref) when you are typing = (copy/move), & (borrow/ref), * (deref)


Q&A

Join Slido: Enter #code to vote and ask questions

app.sli.do/event/pdmHAZWcGDERsxZzcx6i7g


ABOUT ME

If you are looking for a full time and fully remote 10+ years web developer (and 3+ years of team lead) with production experience in AWS, MongoDB, MySQL, Elixir, Phoenix, JavaScript, TypeScript, React, React Native, NativeBase, OpenAPI, Apollo GraphQL, Docker, Shell.

Please write to [email protected]