Skip to content

Instantly share code, notes, and snippets.

@HarrisonMc555
Created February 26, 2020 19:23
Show Gist options
  • Save HarrisonMc555/ac7e7488a3d14174524faf99d7749e20 to your computer and use it in GitHub Desktop.
Save HarrisonMc555/ac7e7488a3d14174524faf99d7749e20 to your computer and use it in GitHub Desktop.
Welcome to Rust | Slide notes

Welcome To Rust

Overview

  1. Background
    • What is Rust?
    • Why Rust?
  2. Examples
  3. Comparison to other languages
    • Comparisons to languages with manual memory management
    • Comparisons to garbage collected languages
    • Comparisons to most other languages
  4. Getting Started
  5. Ownership
  6. Resources

Background

What is Rust?

  • A systems programming language
  • Statically typed
  • Strongly typed
  • Implicitly typed (sometimes)

Why Rust?

  • Performance
  • No runtime or garbage collection
  • Zero-cost abstractions
  • Amazing optimizations—for free!
  • Reliability
  • Abstractions that minimize bugs
  • Ownership
  • Data races are prevented by the compiler (!!!)
  • Thread safety is enforced by the compiler (!!!)
  • Productivity
    • Powerful type system
    • Useful error messages
    • Great package manager (cargo)

Examples

Hello, world!

fn main() {
    println!("Hello, world!");
}

Output

Hello, world!
  • C-like syntax

Functions

fn main() {
    println!("The answer is {}", combine(20, 21));
}

fn combine(x: u32, y: u32) -> u32 {
    let x2 = x + 1;
    x2 + y
}

Output

The answer is 42
  • Functions denoted with fn
  • Variable declarations are done with let
  • Types come after name (for both functions and variables)
  • Integer types specify their size and signed-ness
    • u32 = unsigned 32-bit integer
  • Last statement is implicitly the return value

Structures

#[derive(Debug)]
struct Point {
    x: f64,
    y: f64,
}

impl Point {
    fn distance(&self) -> f64 {
        (self.x * self.x + self.y * self.y).sqrt()
    }
}

fn main() {
    let point = Point { x: 1.5, y: -2.0 };
    println!("Distance for {:?} is {}", point, point.distance());
}
  • Rust has structs, not classes
  • Implementation is separate from definition
  • You can define "methods" on structs
  • Type inference means you almost never have to repeat yourself!

Enumerations

enum Direction {
    North,
    South,
    East,
    West,
}

fn main() {
    let direction = Direction::East;
    let turn = match direction {
        Direction::North => "forward",
        Direction::South => "backward",
        Direction::East => "right",
        Direction::West => "left",
    };
}
  • Enumerated types use enum
  • Pattern matching is done with match
  • A match block (and pretty much everything else) can be assigned to a value
  • match expressions must be exhaustive or have a "default" case

Comparisons to Other Programming Languages

Comparisons To Languages With Manual Memory Management

Comparisons To Languages With Manual Memory Management C/C++

  • Memory safety
  • Use malloc and free correctly or have undefined behavior and security issues (segfaults!)
  • According to Microsoft, 70% of all security bugs are memory safety issues (link)
  • Memory safety is impossible in safe Rust!

Comparisons To Languages With Manual Memory Management C/C++

  • Tooling
  • rustc: Compiler with amazing error messages
  • cargo: Modern build system that makes import dependencies easy
  • rustfmt: A code formatter that everyone uses
  • clippy: An Excellent linter
  • cargo doc: Run documentation as tests

Comparisons To Languages With Manual Memory Management C/C++

  • Powerful abstractions
  • No null (or segmentation faults)!
  • Return Options and Results instead of error codes and mutating parameters
  • Powerful trait system
  • "Functional programming"-esque tools (map, filter, reduce, etc.)

Comparisons To Garbage Collected Languages

  • Faster
  • No garbage collection overhead
  • Compiler makes lots of optimizations
  • More data on the stack vs. the heap
  • Less memory
  • No garbage collection overhead
  • Zero-cost abstractions (e.g. iterators)
  • Garbage collected languages need at least five times as much memory to perform as well as explicit memory management (link)
  • Predictable performance
  • Data is deallocated deterministically
  • No garbage collection "spikes"
  • Suitable for systems programming
  • Access to raw memory when needed
  • No runtime

Comparisons To Most Other Languages

  • Data races are prevented by the compiler—fearless concurrency!
  • Explicit control over mutability and ownership

Getting Started

Getting Started

  1. Install Rust compiler and friends:
    • curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  2. Create a new Rust project ("crate")
    • cargo new <name>
  3. Edit source file
    • $EDITOR src/main.rs
  4. Compile and run
    • cargo run

Ownership

Ownership

The Rust compiler enforces three rules for ownership:

  1. Each value in Rust has a variable that’s called its owner.
  2. There can only be one owner at a time.
  3. When the owner goes out of scope, the value will be dropped.

Ownership example

fn main() {
    let x = 15;
    if x > 10 {
        // s is not yet declared, so not valid
        let s = String::from("Hello"); // s is valid here onward
        println!("{}, world!", s)
    } // s goes out of scope, no longer valid
    // println!("{}", s); // This would be illegal
}
  • Data is dropped (deallocated) when its owner goes out of scope

Use after move

fn main() {
    let s1 = String::from("hello");
    let s2 = s1; // s1 is moved here

    // Try to use s1 after move
    println!("{}, world!", s1);
    println!("{}, you too!", s2);
}
error[E0382]: borrow of moved value: `s1`
 --> src/main.rs:5:28
  |
2 |     let s1 = String::from("hello");
  |         -- move occurs because `s1` has type `std::string::String`,
  |            which does not implement the `Copy` trait
3 |     let s2 = s1;
  |              -- value moved here
4 |
5 |     println!("{}, world!", s1);
  |                            ^^ value borrowed here after move

error: aborting due to previous error

For more information about this error, try `rustc --explain E0382`.
error: could not compile `e03-ownership-wrong`.

To learn more, run the command again with --verbose.

Use after move

fn main() {
    let s1 = String::from("hello");
    let s2 = s1; // s1 is moved here

    // Try to use s1 after move
    println!("{}, world!", s1);
    println!("{}, you too!", s2);
}
  • Types with dynamic sizes (vectors, strings, etc.) need to be stored on the heap
  • Primitive (and Copy) types can be copied without being moved

Borrowing

fn main() {
    let s = String::from("hello");
    let desc = description(&s);
    println!("{}: {}", s, desc);
}

fn description(string: &str) -> String {
    if string.len() > 10 {
        String::from("long")
    } else {
        String::from("short")
    }
}
  • If you don't want to give ownership away, you can let something "borrow" your data
  • You can either give away many immutable references or one mutable reference

Resources

Resources

The End

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment