Rust vs Swift: Comparação Técnica 2026 | Rust Brasil

Rust vs Swift: ownership, memory management, performance, ecosistema e quando usar cada linguagem. Comparação detalhada.

Introdução

Rust e Swift são duas linguagens modernas que compartilham diversas similaridades: ambas priorizam segurança, possuem sistemas de tipos expressivos, usam enums com dados associados e favorecem tratamento explícito de erros. Porém, seus ecossistemas e casos de uso são significativamente diferentes.

Swift, criada pela Apple em 2014, é a linguagem padrão para desenvolvimento iOS, macOS, watchOS e tvOS. Nos últimos anos, expandiu para server-side com frameworks como Vapor e para desenvolvimento cross-platform com Swift on Server. Rust é uma linguagem de sistemas de propósito geral, usada de infraestrutura a WebAssembly, sem vínculos com nenhuma plataforma específica.

Este artigo é para desenvolvedores Swift curiosos sobre Rust, desenvolvedores Rust que trabalham no ecossistema Apple, e qualquer pessoa que queira entender como essas duas linguagens modernas se comparam.

Tabela Comparativa

AspectoRustSwift
Gerenciamento de memóriaOwnership + Borrow CheckerARC (Automatic Reference Counting)
Ciclos de referênciaImpossíveis (ownership linear)Possíveis (weak/unowned necessários)
PerformanceEquivalente a C/C++Próxima de C (ARC tem overhead)
Concorrênciaasync/await + Send/Sync (compile-time)Swift Concurrency + actors (runtime)
Null safetyOption<T>Optional (T?)
Pattern matchingmatch (exaustivo)switch (exaustivo)
GenericsMonomorphization + TraitsSpecialization + Protocols
EcossistemaCross-platform, crates.ioApple-centric, Swift Package Manager
IDEVS Code, RustRover, NeovimXcode, VS Code
Cross-platformExcelente (Linux, Windows, macOS, Wasm)Bom (Linux, macOS, Windows experimental)

ARC vs Ownership: Modelos de Memória

A diferença mais fundamental entre Rust e Swift é como gerenciam memória.

Swift: Automatic Reference Counting

class Documento {
    let titulo: String
    var conteudo: String

    init(titulo: String, conteudo: String) {
        self.titulo = titulo
        self.conteudo = conteudo
        print("Criando: \(titulo)")
    }

    deinit {
        print("Destruindo: \(titulo)")
    }
}

func exemplo() {
    let doc1 = Documento(titulo: "Relatório", conteudo: "...")
    let doc2 = doc1  // Incrementa reference count (agora RC = 2)

    // Ambos doc1 e doc2 apontam para o MESMO objeto
    doc2.conteudo = "Atualizado"
    print(doc1.conteudo)  // "Atualizado" — mesmo objeto!
}
// RC chega a 0, deinit é chamado

// PERIGO: ciclos de referência
class No {
    var proximo: No?  // Strong reference
    deinit { print("No destruído") }
}

func criarCiclo() {
    let a = No()
    let b = No()
    a.proximo = b
    b.proximo = a  // Ciclo! Memory leak — deinit nunca é chamado
}

Rust: Ownership

struct Documento {
    titulo: String,
    conteudo: String,
}

impl Documento {
    fn new(titulo: &str, conteudo: &str) -> Self {
        println!("Criando: {titulo}");
        Documento {
            titulo: titulo.to_string(),
            conteudo: conteudo.to_string(),
        }
    }
}

impl Drop for Documento {
    fn drop(&mut self) {
        println!("Destruindo: {}", self.titulo);
    }
}

fn exemplo() {
    let doc1 = Documento::new("Relatório", "...");
    let doc2 = doc1;  // MOVE — doc1 não é mais válido

    // doc1.conteudo; // ERRO: value used after move

    // Para compartilhar, use referências explícitas:
    let doc3 = Documento::new("Outro", "...");
    let ref1 = &doc3;
    let ref2 = &doc3;
    println!("{} {}", ref1.titulo, ref2.titulo); // OK: múltiplas referências imutáveis
}

// Ciclos de referência: impossíveis com ownership linear
// Se você precisar de grafos cíclicos, use Rc<RefCell<T>> explicitamente

A diferença chave: Swift usa contagem de referências automática (ARC), que tem overhead em runtime (incrementar/decrementar contadores atomicamente) e permite ciclos de referência que causam memory leaks. Rust usa ownership linear, que não tem overhead em runtime e torna ciclos de referência estruturalmente impossíveis no caso comum.

Enums e Pattern Matching: Surpreendentemente Similares

Ambas as linguagens têm enums com dados associados e pattern matching exaustivo:

Swift

enum Resultado<T> {
    case sucesso(T)
    case erro(String)
}

enum Forma {
    case circulo(raio: Double)
    case retangulo(largura: Double, altura: Double)
    case triangulo(base: Double, altura: Double)
}

func area(_ forma: Forma) -> Double {
    switch forma {
    case .circulo(let raio):
        return .pi * raio * raio
    case .retangulo(let largura, let altura):
        return largura * altura
    case .triangulo(let base, let altura):
        return base * altura / 2.0
    }
}

let formas: [Forma] = [
    .circulo(raio: 5.0),
    .retangulo(largura: 3.0, altura: 4.0),
    .triangulo(base: 6.0, altura: 3.0),
]

for forma in formas {
    print("Área: \(area(forma))")
}

Rust

use std::f64::consts::PI;

enum Forma {
    Circulo { raio: f64 },
    Retangulo { largura: f64, altura: f64 },
    Triangulo { base: f64, altura: f64 },
}

fn area(forma: &Forma) -> f64 {
    match forma {
        Forma::Circulo { raio } => PI * raio * raio,
        Forma::Retangulo { largura, altura } => largura * altura,
        Forma::Triangulo { base, altura } => base * altura / 2.0,
    }
}

fn main() {
    let formas = vec![
        Forma::Circulo { raio: 5.0 },
        Forma::Retangulo { largura: 3.0, altura: 4.0 },
        Forma::Triangulo { base: 6.0, altura: 3.0 },
    ];

    for forma in &formas {
        println!("Área: {:.2}", area(forma));
    }
}

A sintaxe é notavelmente similar. Desenvolvedores Swift se sentirão em casa com enums e pattern matching em Rust — a transferência de conhecimento é direta.

Concorrência: Actors vs Send/Sync

Swift Concurrency (Actors)

actor ContaBancaria {
    private var saldo: Double

    init(saldoInicial: Double) {
        self.saldo = saldoInicial
    }

    func depositar(_ valor: Double) {
        saldo += valor
    }

    func sacar(_ valor: Double) -> Bool {
        guard saldo >= valor else { return false }
        saldo -= valor
        return true
    }

    func consultarSaldo() -> Double {
        return saldo
    }
}

func exemplo() async {
    let conta = ContaBancaria(saldoInicial: 1000.0)

    await conta.depositar(500.0)
    let sucesso = await conta.sacar(200.0)
    let saldo = await conta.consultarSaldo()
    print("Saldo: \(saldo), Saque OK: \(sucesso)")
}

Rust com Tokio e Mutex

use std::sync::Arc;
use tokio::sync::Mutex;

struct ContaBancaria {
    saldo: f64,
}

impl ContaBancaria {
    fn new(saldo_inicial: f64) -> Self {
        ContaBancaria { saldo: saldo_inicial }
    }

    fn depositar(&mut self, valor: f64) {
        self.saldo += valor;
    }

    fn sacar(&mut self, valor: f64) -> bool {
        if self.saldo >= valor {
            self.saldo -= valor;
            true
        } else {
            false
        }
    }

    fn consultar_saldo(&self) -> f64 {
        self.saldo
    }
}

#[tokio::main]
async fn main() {
    let conta = Arc::new(Mutex::new(ContaBancaria::new(1000.0)));

    {
        let mut c = conta.lock().await;
        c.depositar(500.0);
    }

    let sucesso = {
        let mut c = conta.lock().await;
        c.sacar(200.0)
    };

    let saldo = {
        let c = conta.lock().await;
        c.consultar_saldo()
    };

    println!("Saldo: {saldo}, Saque OK: {sucesso}");
}

Swift actors são mais ergonômicos — o isolamento de dados é automático. Em Rust, você usa Arc<Mutex<T>> e gerencia locks manualmente, mas o compilador garante em tempo de compilação (via traits Send e Sync) que você não tem data races.

Comparação de Performance

Benchmarks

BenchmarkRustSwiftDiferença
Fibonacci(45)3,2s3,8s~19% Rust
Sort 10M inteiros0,48s0,55s~15% Rust
ARC/Drop overhead0 (ownership)~5-15% (ARC)Rust sem overhead
Parsing JSON 100MB0,08s (serde)0,15s (Codable)~47% Rust
HTTP req/s850k (axum)280k (Vapor)~3x Rust
Tamanho do binário~3 MB~8 MB~63% Rust
Memória idle (servidor)~5 MB~15 MB~67% Rust

A principal vantagem de performance do Rust sobre Swift vem da ausência de ARC. Em código com muitas alocações e referências (como servidores web), a contagem de referências atômica do ARC adiciona overhead mensurável.

Cross-Platform: Onde Cada Uma Brilha

Swift

  • Ecossistema Apple: iOS, macOS, watchOS, tvOS — tooling e integração incomparáveis
  • SwiftUI: framework declarativo para interfaces nativas
  • Server-side: Vapor e Hummingbird, mas adoção ainda pequena fora da Apple
  • Linux: suporte oficial, mas ecossistema limitado
  • Windows: suporte experimental, ainda não maduro

Rust

  • Linux, macOS, Windows: suporte de primeira classe em todas
  • WebAssembly: melhor suporte para Wasm entre linguagens de sistemas
  • Embarcados: suporte crescente para ARM, RISC-V, sem_std
  • Android (NDK): boa integração via C ABI
  • iOS: possível via C ABI, mas menos ergonômico que Swift

Para configurar Rust no macOS, veja nosso guia de instalação para macOS.

Quando Usar Swift

Escolha Swift quando:

  • Desenvolvimento Apple: iOS, macOS, watchOS — sem contestação
  • SwiftUI/UIKit: interfaces nativas para plataformas Apple
  • Server-side no ecossistema Apple: se a equipe já domina Swift
  • Prototipagem com Playgrounds: exploração rápida de ideias
  • Kotlin Multiplatform não atende: Swift é mais natural para devs Apple

Quando Usar Rust

Escolha Rust quando:

  • Cross-platform real: o mesmo código em Linux, macOS, Windows e Wasm
  • Performance máxima: sem overhead de ARC, controle total de memória
  • Infraestrutura e sistemas: servidores, CLIs, proxies, bancos de dados
  • Componentes de alta performance para iOS/macOS: via FFI como biblioteca C
  • WebAssembly: módulos Wasm de alta performance

Conclusão e Recomendação

Para desenvolvimento no ecossistema Apple, Swift é a escolha óbvia e correta. Xcode, SwiftUI, e a integração nativa com as APIs da Apple não têm equivalente em Rust. Mesmo para server-side, se sua equipe é de Swift, usar Vapor faz sentido.

Para projetos cross-platform, infraestrutura e alta performance, Rust é a melhor escolha. Se você precisa que o mesmo código rode eficientemente em Linux, macOS, Windows e WebAssembly, Rust tem suporte muito superior.

Se você é desenvolvedor Swift, aprender Rust será mais fácil do que para a maioria dos programadores — os conceitos de enums, pattern matching, generics e tratamento explícito de erros são muito similares. A maior novidade será o ownership system, que substitui o ARC com que você já está acostumado.

A combinação ideal para projetos Apple que precisam de componentes de alta performance é: Swift para a UI e lógica de aplicação, Rust para bibliotecas de processamento, conectados via C ABI.


Veja Também