Porque Você Deveria Aprender Rust

Me

A languagem mais amada segundo o StackOverflow Survey 2019

... pelo 4⁰ ano seguido.

"Low Level Language with High Level Abstractions"

Resultado final com performance semelhante ao C...

... mas com abstrações em algo nível

  • Strings sem tamanho fixo
  • Listas
  • Mapas

Imutabilidade por Default


fn main() {
    let a = 2;
    a = 3;
    println!("{}", a);
}
                        

3 |     let a = 2;
  |         -
  |         |
  |         first assignment to `a`
  |         help: make this binding mutable: `mut a`
4 |     a = 3;
  |     ^^^^^ cannot assign twice to immutable variable
                        

3 |     let a = 2;
  |         -
  |         |
  |         first assignment to `a`
  |         help: make this binding mutable: `mut a`
4 |     a = 3;
  |     ^^^^^ cannot assign twice to immutable variable
                        

3 |     let a = 2;
  |         -
  |         |
  |         first assignment to `a`
  |         help: make this binding mutable: `mut a`
4 |     a = 3;
  |     ^^^^^ cannot assign twice to immutable variable
                        

fn main() {
    let mut a = 2;
    a = 3;
    println!("{}", a);
}
                        

Borrow Checker


a = String::from("hello");
                        
"Variável a tem o valor "hello""
"Posição de memória apontada por a tem o valor "hello""

0x3f5cbf89 = "hello"
                            
A language that doesn't affect the way you think about programming, is not worth knowing.
-- Alan Perlis, "ALGOL"

fn main() {
    let a = String::from("hello");
    let _b = a;
    println!("{}", a)
}
                        

error[E0382]: borrow of moved value: `a`
 --> src/main.rs:5:20
  |
4 |     let _b = a;
  |              - value moved here
5 |     println!("{}", a)
  |                    ^ value borrowed here after move
  |
  = note: move occurs because `a` has type 
    `std::string::String`, which does not 
    implement the `Copy` trait
                        

E se eu precisar acessar a variável em mais de um lugar?

References


fn main() {
    let a = String::from("hello");
    let _b = &a;
    println!("{}", a)
}
                        

Regras do Borrow Checker

Uma região de memória tem apenas um dono.

Passar um valor (região de memória) de uma variável para outra, troca o dono.

A região é desalocada quando o dono sair de escopo.

Regras do Borrow Checker

Uma região de memória pode ter infinitas referências.

... desde que elas não durem mais do que o dono.

Regras do Borrow Checker

É possível ter uma referência mutável de uma região de memória.

... mas para haver uma referência mutável ela deve ser a única referência.

presente := Presente { ... }
canal <- presente
 
presente := Presente { ... }
canal <- presente
presente.abrir()

GC?

GC não é determinístico.

(mas ainda tem um container que é um contador de refências)
Swift 5 Exclusivity Enforcement

Hora da anedota!

localtime

SimpleDateFormatter

Rust resolveria isso?

Não

... na verdade, nem ia compilar.

Tipos Algébricos

enum


enum IpAddr {
   V4,
   V6
}
                        

enum IpAddr {
    V4(String),
    V6(String),
}
                        

let home = IpAddr::V4(String::from("127.0.0.1");

match home {
    V4(address) => println!("IPv4 addr: {}", address),
    V6(address) => println!("Ipv6 addr: {}", address),
}
                        

enum Option<T> {
    Some(T),
    None
}
                        

Error Control


try:
    something()
except Exception:
    pass
                        

try {
   something();
} catch (Exception ex) {
   System.out.println(ex);
}
                        

FILE* f = fopen("someting.txt", "wb");
fprintf(f, "Done!");
fclose(f);
                        
Onde o erro foi tratado nisso?

enum Result<T, E> {
    Ok(T),
    Err(E),
}
                        

match File::create("something.txt") {
    Ok(fp) => fp.write_all(b"Hello world"),
    Err(err) => println!("Failure! {}", err),
}
                        

match File::create("something.txt") {
    Ok(fp) => match fp.write_all(b"Hello world") {
        Ok(_) => (),
        Err(err) => println!("Can't write! {}", err),
    }
    Err(err) => println!("Failure! {}", err),
}
                        

let mut file = File::create("something.txt").unwrap();
file.write(b"Hello world").unwrap();
                        

let mut file = File::create("something.txt")?;
file.write(b"Hello world")?;
OK(())
                        

Macros

?

Structs


struct Present {
    package_color: String,
    content: String
}
                        

Traits/Generics


enum Result<T, E> {
    Ok(T),
    Err(E),
}
                        

trait Summary {
    fn summarize(&self) -> String;
}
                        

struct Super {
    phrase: String
}

impl Summary for Super {
    fn summarize(&self) -> String {
        self.phrase
            .split_whitespace()
            .map(|word| word.chars().nth(0).unwrap())
            .collect();
    }
}
                        

fn get_summary(summarizable: T) -> String
    where T: Summary
{
    ...
}
                        

Structs genéricas


struct Point<T> {
    x: T,
    y: T
}
                        

Tests


#[cfg(test)]
mod tests {
    #[test]
    fn testing() {
    }
}
						

$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished dev [unoptimized + debuginfo] target(s) in 0.22 secs
     Running target/debug/deps/adder-ce99bcc2479f4607

running 1 test
test tests::testing ... ok
                        

Crazy stuff

How Rust’s standard library was vulnerable for years and nobody noticed
No, the problem isn’t “bad coders”
4.5k issues no Github
rustup
stable-x86_64-pc-windows-msvc
armv7-unknown-linux-gnueabihf
wasm32-unknown-unknown (WebAssembly)

Falando em WASM...

WASM

wasm-pack

WASI

The WebAssembly System Interface

Bibliotecas

Rayon


fn sum_of_squares(input: &[i32]) -> i32 {
    input.iter()
         .map(|&i| i * i)
         .sum()
}
                        

Rayon


fn sum_of_squares(input: &[i32]) -> i32 {
    input.par_iter()
         .map(|&i| i * i)
         .sum()
}
                        

Log-Derive


#[logfn(ok = "TRACE", err = "ERROR")]
fn call_isan(num: &str) -> Result<Success, Error> {
    if num.len() >= 10 && num.len() <= 15 {
        Ok(Success)
    } else {
        Err(Error)
    }
}