Rust Overview

Sven Kube

Table of Contents

  • Rust Compiler
  • Ownership
  • Pattern Matching
  • Error Handling
  • Traits

Rust Compiler

Variables and Mutability


fn main() {
    let x = 42;

    x = 773;

    println!("{}", x);
}
      


error[E0384]: cannot assign twice to immutable variable `x`
 --> test.rs:5:5
  |
3 |     let x = 42;
  |         - first assignment to `x`
4 | 
5 |     x = 773;
  |     ^^^^^^^ cannot assign twice to immutable variable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0384`.

          

Variables and Mutability


  fn main() {
      let mut x = 42;
  
      x = 773;
  
      println!("{}", x);
  }
        

  
warning: value assigned to `x` is never read
 --> test.rs:2:13
  |
2 |     let mut x = 42;
  |             ^
  |
  = note: #[warn(unused_assignments)] on by default
  = help: maybe it is overwritten before being read?

  
            

In C++:


int* bad_ptr(){
    int some_int = 42;

    return &some_int;
}

int main(){
  int* some_ptr = bad_ptr();

  std::cout << *some_ptr << std::endl;
}
          

Compiles with a warning


“./return-local-addr” terminated by signal SIGSEGV (Address boundary error)
            

In Rust:


fn bad_ptr<'a>(x: i32) -> &'a i32 {
    let y : &i32 = &x;
    y
}

fn main() {
    let a = 42;
    let b : i32 = *bad_ptr(a);

    println!("a: {}, b: {}", a, b);
}
          

Rust-Compiler says:


error[E0597]: `x` does not live long enough
 --> return-local-addr.rs:2:21
  |
2 |     let y : &i32 = &x;
  |                     ^ borrowed value does not live long enough
3 |     y
4 | }
  | - borrowed value only lives until here
  |
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 1:12...
 --> return-local-addr.rs:1:12
  |
1 | fn bad_ptr<'a>(x: i32) -> &'a i32 {
  |            ^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0597`.
          

Ownership

Ownership Rules

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

References and Borrowing


fn main() {
    let s1 = String::from("Coding Students");

    let len = calculate_length(&s1);

    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}
          

References and Borrowing


fn main() {
    let mut s = String::from("hello");

    change(&mut s);
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}
          

The Rules of References

  • At any given time, you can have either one mutable reference or any number of immutable references.
  • References must always be valid.

Pattern Matching

Patterns


let x = 1;

match x {
    1 => println!("one"),
    2 => println!("two"),
    3 => println!("three"),
    _ => println!("anything"),
}           
          

Multiple patterns


let x = 1;

match x {
    1 | 2 => println!("one or two"),
    3 => println!("three"),
    _ => println!("anything"),
}
          

Destructuring


struct Point {
    x: i32,
    y: i32,
}

let some_point = Point { x: 0, y: 1 };

match some_point {
    Point { x, y } => println!("({}, {})", x, y),
}
          

Error Handling

Reading a file

With Type-Inference:


use std::fs::File;

fn main() {
    let f = File::open("hello.txt");
}
          

Without:


use std::fs::File;

fn main() {
    let f: std::result::Result<std::fs::File, std::io::Error> = File::open("hello.txt");
}
          

let f = File::open("hello.txt");

let f = match f {
    Ok(file) => file,
    Err(error) => {
        panic!("Problem opening the file: {:?}", error)
    },
};
          

let f = File::open("hello.txt").unwrap();

let f = File::open("hello.txt").expect("Failed to open hello.txt");
          

Traits


struct Point {
    x: f64,
    y: f64,
}

fn point_to_string(point: &Point) -> String { ... }

impl Point {
    fn to_string(&self) -> String { ... }
}
          

The Hash Trait


trait Hash {
    fn hash(&self) -> u64;
}
          

impl Hash for bool {
    fn hash(&self) -> u64 {
        if *self { 0 } else { 1 }
    }
}

impl Hash for i64 {
    fn hash(&self) -> u64 {
        *self as u64
    }
}
          
Rust Book

There is more:

  • rustfmt
  • Cargo
  • Clippy
  • rocket
  • serde
  • diesel
  • ...

Slides:

https://github.com/SvenKube/Coding-Students-Meetup-Rust-Overview