Porque Você Deveria Aprender Rust

Porque Você DEVE Aprender Rust

Me

JulioBiason.me

História

  • Criada em 2006 por Graydon Hoare.
  • Patrocinada pela Mozilla em 2009.
  • Versão 1.0 em 2015.
  • Versão atual: 1.70

História

Basic (com números e estruturado), dBase III Plus, Clipper, Pascal, Cobol, Delphi (ObjectPascal), C, C++, ActionScript (Flash), PHP, JavaScript, Python, Objective-C, Clojure, Java, Scala , Rust.

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

O Que Rust Tem de Diferente?

Borrow Checker


let 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"
                        

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
                    

Para ter mais de um acesso a mesma posição de memória, referências


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.

Drop


pub fn drop<T>(_x: T) { }
                    

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.

Microsoft: 70 percent of all security bugs are memory safety issues

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.

Sem condições de corrida (race conditions)

Regras do Borrow Checker

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

Evita problemas de double-free ou não usar free e sem precisar de garbage collector.

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.

Sem dangling-pointers.

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.

Condição de corrida

Além do borrow Checker

  • Uso extenso de iteradores para evitar out-of-bounds.
  • Bound-check para casos sem iteradores (com custo).
  • Sem coerção de tipos.

MISRA-C / MISRA-C++

Conjunto de regras para uso de C/C++ para equipamentos aonde vidas humanas estão em jogo.

75% das regras já são obrigatórias pelo compilador (108 dos 141 casos)

A Linguagem Mais Amada

A linguagem mais amada segundo o StackOverflow Survey 2022

... pelo 7⁰ ano seguido.

Green Energy Language

Compilador Chato mas Amigável


fn main() -> u8 {
    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
                    

Verificar Erros é Obrigatório


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(())
                    

Cargo

"Cargo is the Rust package manager"

"Cargo downloads your Rust package’s dependencies, compiles your packages, makes distributable packages, and uploads them to crates.io, the Rust community’s package registry."

Ferramenta Para Testes Já Presente


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

Tests


$ 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
                    

Desenvolvimento Aberto

4.5k issues no Github

E agora?