Rust: Programação de Sistemas Segura

Aprenda Rust, a linguagem que garante segurança de memória sem garbage collector


Rust: Programação de Sistemas Segura
1 Carregando...

Rust: Programação de Sistemas Segura

Rust é uma linguagem de programação de sistemas que combina performance de baixo nível com garantias de segurança em tempo de compilação. Criada pela Mozilla e lançada em 2010, Rust elimina classes inteiras de bugs relacionados à memória através de seu sistema de ownership único, sem sacrificar a performance.

Por que Rust? Rust foi votada como a “linguagem mais amada” no Stack Overflow Survey por 8 anos consecutivos. Empresas como Microsoft, Google, Amazon e Discord usam Rust em produção.

Conceitos Fundamentais

Ownership, Borrowing e Lifetimes

O sistema de ownership é o coração de Rust:

// Ownership - cada valor tem um único dono
fn main() {
    let s1 = String::from("hello");
    let s2 = s1; // s1 é movido para s2
    // println!("{}", s1); // ERRO! s1 não é mais válido
    println!("{}", s2); // OK
}

// Borrowing - referências imutáveis
fn calcular_tamanho(s: &String) -> usize {
    s.len()
}

// Borrowing mutável
fn adicionar_texto(s: &mut String) {
    s.push_str(" world");
}

fn main() {
    let mut texto = String::from("hello");
    
    // Múltiplas referências imutáveis são permitidas
    let r1 = &texto;
    let r2 = &texto;
    println!("{} e {}", r1, r2);
    
    // Apenas UMA referência mutável por vez
    let r3 = &mut texto;
    r3.push_str("!");
    println!("{}", r3);
}

// Lifetimes - garantem que referências são válidas
fn maior<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

Tipos de Dados

// Tipos primitivos
let inteiro: i32 = 42;
let flutuante: f64 = 3.14;
let booleano: bool = true;
let caractere: char = '🦀';

// Tuplas
let tupla: (i32, f64, &str) = (42, 3.14, "rust");
let (x, y, z) = tupla; // Destructuring

// Arrays (tamanho fixo)
let array: [i32; 5] = [1, 2, 3, 4, 5];
let primeiro = array[0];

// Vectors (tamanho dinâmico)
let mut vec: Vec<i32> = vec![1, 2, 3];
vec.push(4);

// Strings
let s1: &str = "string literal"; // String slice
let s2: String = String::from("owned string");

// HashMap
use std::collections::HashMap;
let mut mapa: HashMap<&str, i32> = HashMap::new();
mapa.insert("chave", 42);

Structs e Enums

// Struct
#[derive(Debug, Clone)]
struct Usuario {
    nome: String,
    email: String,
    idade: u32,
    ativo: bool,
}

impl Usuario {
    // Construtor
    fn novo(nome: String, email: String, idade: u32) -> Self {
        Self {
            nome,
            email,
            idade,
            ativo: true,
        }
    }
    
    // Método
    fn saudar(&self) -> String {
        format!("Olá, {}!", self.nome)
    }
    
    // Método mutável
    fn desativar(&mut self) {
        self.ativo = false;
    }
}

// Enum com dados
enum Mensagem {
    Sair,
    Mover { x: i32, y: i32 },
    Escrever(String),
    MudarCor(u8, u8, u8),
}

// Pattern matching
fn processar_mensagem(msg: Mensagem) {
    match msg {
        Mensagem::Sair => println!("Saindo..."),
        Mensagem::Mover { x, y } => println!("Movendo para ({}, {})", x, y),
        Mensagem::Escrever(texto) => println!("Texto: {}", texto),
        Mensagem::MudarCor(r, g, b) => println!("Cor: RGB({}, {}, {})", r, g, b),
    }
}

// Option e Result
fn dividir(a: f64, b: f64) -> Option<f64> {
    if b == 0.0 { None } else { Some(a / b) }
}

fn ler_arquivo(caminho: &str) -> Result<String, std::io::Error> {
    std::fs::read_to_string(caminho)
}

Traits

// Definindo uma trait
trait Resumivel {
    fn resumo(&self) -> String;
    
    // Implementação padrão
    fn descricao(&self) -> String {
        format!("Resumo: {}", self.resumo())
    }
}

// Implementando trait
struct Artigo {
    titulo: String,
    autor: String,
    conteudo: String,
}

impl Resumivel for Artigo {
    fn resumo(&self) -> String {
        format!("{} por {}", self.titulo, self.autor)
    }
}

// Trait bounds em generics
fn imprimir_resumo<T: Resumivel>(item: &T) {
    println!("{}", item.resumo());
}

// Múltiplas trait bounds
fn processar<T: Resumivel + Clone + std::fmt::Debug>(item: T) {
    println!("{:?}", item);
}

// Where clause para legibilidade
fn funcao_complexa<T, U>(t: T, u: U) -> String
where
    T: Resumivel + Clone,
    U: std::fmt::Display,
{
    format!("{}: {}", t.resumo(), u)
}

Tratamento de Erros

use std::fs::File;
use std::io::{self, Read};

// Propagação de erros com ?
fn ler_usuario() -> Result<String, io::Error> {
    let mut arquivo = File::open("usuario.txt")?;
    let mut conteudo = String::new();
    arquivo.read_to_string(&mut conteudo)?;
    Ok(conteudo)
}

// Erro customizado
#[derive(Debug)]
enum MeuErro {
    Io(io::Error),
    Parse(std::num::ParseIntError),
    Customizado(String),
}

impl From<io::Error> for MeuErro {
    fn from(err: io::Error) -> Self {
        MeuErro::Io(err)
    }
}

// Usando anyhow para simplificar
// use anyhow::{Context, Result};
// fn funcao() -> Result<()> {
//     let arquivo = File::open("config.txt")
//         .context("Falha ao abrir arquivo de configuração")?;
//     Ok(())
// }

Concorrência

use std::thread;
use std::sync::{Arc, Mutex};

// Threads básicas
fn main() {
    let handle = thread::spawn(|| {
        for i in 1..10 {
            println!("Thread: {}", i);
        }
    });
    
    for i in 1..5 {
        println!("Main: {}", i);
    }
    
    handle.join().unwrap();
}

// Compartilhando dados entre threads
fn contador_compartilhado() {
    let contador = Arc::new(Mutex::new(0));
    let mut handles = vec![];
    
    for _ in 0..10 {
        let contador = Arc::clone(&contador);
        let handle = thread::spawn(move || {
            let mut num = contador.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }
    
    for handle in handles {
        handle.join().unwrap();
    }
    
    println!("Resultado: {}", *contador.lock().unwrap());
}

// Async/await com tokio
// use tokio;
// 
// #[tokio::main]
// async fn main() {
//     let response = reqwest::get("https://api.exemplo.com")
//         .await
//         .unwrap()
//         .text()
//         .await
//         .unwrap();
//     println!("{}", response);
// }

Ferramentas do Ecossistema

FerramentaPropósito
cargoGerenciador de pacotes e build
rustfmtFormatador de código
clippyLinter com dicas avançadas
rust-analyzerLSP para IDEs

Checklist de Aprendizado

  • Entender ownership, borrowing e lifetimes
  • Dominar structs, enums e pattern matching
  • Aprender traits e generics
  • Estudar tratamento de erros com Result e Option
  • Explorar concorrência e async/await
  • Construir um projeto CLI
  • Contribuir para projetos Rust open source

Recursos Essenciais

Citação

“Rust é uma linguagem que respeita o tempo e a inteligência do desenvolvedor.” - Steve Klabnik


Rust pode parecer desafiador no início, mas as garantias de segurança que oferece valem o investimento!