Introdução
Rust e Go são duas das linguagens mais populares da última década, mas foram projetadas com filosofias muito diferentes. Go (ou Golang), criada pelo Google em 2009, prioriza simplicidade, compilação rápida e concorrência acessível. Rust, desenvolvida pela Mozilla e lançada em 2015, foca em segurança de memória, performance zero-cost e controle fino sobre recursos do sistema.
Se você é um desenvolvedor backend, engenheiro de sistemas ou está avaliando qual linguagem adotar para um novo projeto, este artigo vai ajudá-lo a tomar uma decisão informada com base em comparações práticas, benchmarks reais e exemplos de código.
Tabela Comparativa
| Aspecto | Rust | Go |
|---|---|---|
| Paradigma | Multi-paradigma (funcional, imperativo) | Imperativo, concorrente |
| Tipagem | Estática, forte, com inferência | Estática, forte, com inferência |
| Gerenciamento de memória | Ownership + Borrow Checker | Garbage Collector |
| Concorrência | async/await + Tokio (ou threads) | Goroutines + Channels |
| Tempo de compilação | Lento (minutos em projetos grandes) | Muito rápido (segundos) |
| Performance em runtime | Próxima de C/C++ | 2-5x mais lenta que Rust |
| Curva de aprendizado | Íngreme (ownership, lifetimes) | Suave (linguagem simples) |
| Binários | Estáticos, pequenos com strip | Estáticos, maiores (~10MB+) |
| Ecossistema Web | Axum, Actix Web, Rocket | Gin, Echo, Fiber, net/http |
| Uso principal | Sistemas, WebAssembly, embarcados, CLI | Microserviços, DevOps, cloud, CLI |
Modelos de Concorrência
A concorrência é um dos pontos mais debatidos entre Rust e Go. Vamos comparar os dois modelos na prática.
Goroutines em Go
Go usa goroutines, que são threads leves gerenciadas pelo runtime da linguagem. Criar milhares de goroutines é trivial:
package main
import (
"fmt"
"sync"
)
func processar(id int, wg *sync.WaitGroup) {
defer wg.Done()
resultado := 0
for i := 0; i < 1_000_000; i++ {
resultado += i
}
fmt.Printf("Goroutine %d: resultado = %d\n", id, resultado)
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go processar(i, &wg)
}
wg.Wait()
fmt.Println("Todas as goroutines finalizaram.")
}
Async/Await em Rust com Tokio
Rust utiliza async/await com um runtime assíncrono como o Tokio. O modelo é mais explícito, mas oferece controle total sobre alocações e scheduling:
use tokio::task;
async fn processar(id: u32) -> u64 {
let mut resultado: u64 = 0;
for i in 0..1_000_000u64 {
resultado += i;
}
println!("Task {id}: resultado = {resultado}");
resultado
}
#[tokio::main]
async fn main() {
let mut handles = Vec::new();
for i in 0..10 {
handles.push(task::spawn(processar(i)));
}
for handle in handles {
let _ = handle.await.unwrap();
}
println!("Todas as tasks finalizaram.");
}
A diferença fundamental: Go abstrai a complexidade com goroutines e um scheduler embutido. Rust exige que você escolha o runtime (Tokio, async-std) e entenda como futures funcionam, mas em troca oferece zero overhead — você paga apenas pelo que usa.
Para se aprofundar em concorrência no Rust, confira nosso tutorial de concorrência e a receita de async/await básico.
Exemplo Prático: Servidor HTTP
Vamos comparar um servidor HTTP simples que retorna JSON.
Go com net/http
package main
import (
"encoding/json"
"net/http"
)
type Resposta struct {
Mensagem string `json:"mensagem"`
Status int `json:"status"`
}
func handler(w http.ResponseWriter, r *http.Request) {
resp := Resposta{
Mensagem: "Olá do Go!",
Status: 200,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(resp)
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
Rust com Axum
use axum::{routing::get, Json, Router};
use serde::Serialize;
#[derive(Serialize)]
struct Resposta {
mensagem: String,
status: u16,
}
async fn handler() -> Json<Resposta> {
Json(Resposta {
mensagem: "Olá do Rust!".to_string(),
status: 200,
})
}
#[tokio::main]
async fn main() {
let app = Router::new().route("/", get(handler));
let listener = tokio::net::TcpListener::bind("0.0.0.0:8080")
.await
.unwrap();
axum::serve(listener, app).await.unwrap();
}
Ambos os exemplos são concisos, mas note que Go inclui o servidor HTTP na biblioteca padrão, enquanto Rust precisa de crates externas (axum, tokio, serde). Em compensação, o servidor Rust será significativamente mais rápido em benchmarks de alta carga.
Comparação de Performance
Benchmarks de Referência (TechEmpower Framework Benchmarks 2025)
| Métrica | Rust (Axum) | Go (net/http) |
|---|---|---|
| Requisições/segundo (JSON) | ~850.000 | ~350.000 |
| Latência p99 | 0,8 ms | 2,1 ms |
| Uso de memória (idle) | ~2 MB | ~8 MB |
| Uso de memória (sob carga) | ~15 MB | ~60 MB |
| Tempo de startup | < 1 ms | ~5 ms |
| Tamanho do binário (stripped) | ~3 MB | ~11 MB |
Uso de Memória
A maior diferença prática está no consumo de memória. O Garbage Collector do Go introduz overhead tanto em memória quanto em latência (pausas de GC). Rust, com seu modelo de ownership, libera memória deterministicamente sem nenhum GC, resultando em:
- Uso de memória 3-5x menor em cenários típicos de servidor
- Sem pausas de GC, o que garante latência previsível
- Melhor utilização de cache de CPU devido a layouts de memória mais compactos
Tempo de Compilação
Aqui Go vence decisivamente. Um projeto Go de médio porte compila em 2-5 segundos, enquanto o equivalente em Rust pode levar 30-120 segundos. O compilador do Rust faz muito mais trabalho (verificação de ownership, monomorphização de generics, otimizações LLVM), e isso tem um custo.
Tratamento de Erros: Abordagens Distintas
Outra diferença marcante entre Rust e Go está no tratamento de erros.
Go: if err != nil
func lerArquivo(caminho string) (string, error) {
dados, err := os.ReadFile(caminho)
if err != nil {
return "", fmt.Errorf("falha ao ler %s: %w", caminho, err)
}
return string(dados), nil
}
Go usa múltiplos retornos com uma interface error simples. É explícito, mas repetitivo — o padrão if err != nil aparece constantemente no código Go.
Rust: Result<T, E> com o operador ?
fn ler_arquivo(caminho: &str) -> Result<String, std::io::Error> {
let conteudo = std::fs::read_to_string(caminho)?;
Ok(conteudo)
}
Rust usa o tipo Result<T, E> com o operador ? para propagação de erros. É mais conciso e o compilador garante que todos os erros são tratados — é impossível esquecer de verificar um erro em Rust, algo que acontece com frequência em Go quando o desenvolvedor ignora o valor de retorno error.
Sistema de Tipos: Generics e Traits vs Interfaces
Go recebeu generics apenas em 2022 (Go 1.18), enquanto Rust teve generics desde o início. Na prática, os generics do Rust são mais poderosos graças ao sistema de traits:
// Rust: trait com generics — resolvido em tempo de compilação
fn maior<T: PartialOrd>(a: T, b: T) -> T {
if a >= b { a } else { b }
}
// Go: constraint com generics
func maior[T constraints.Ordered](a, b T) T {
if a >= b {
return a
}
return b
}
Ambas as abordagens funcionam, mas Rust permite composição de traits mais complexa, generics com const parameters e tipos associados — funcionalidades que Go não oferece.
Quando Usar Rust
Escolha Rust quando:
- Performance é crítica: sistemas de baixa latência, game engines, processamento de dados em tempo real
- Memória é limitada: embarcados, IoT, serverless (cada MB conta na AWS Lambda)
- Segurança de memória é obrigatória: software de infraestrutura, criptografia, kernels
- WebAssembly: Rust tem o melhor suporte para Wasm entre as linguagens de sistemas
- Você precisa de abstrações zero-cost: generics, traits e iteradores sem overhead
- O sistema de tipos precisa ser expressivo: enums, pattern matching, generics avançados
Quando Usar Go
Escolha Go quando:
- Velocidade de desenvolvimento importa mais: prototipagem rápida, MVPs, startups
- A equipe é grande e diversa: Go é fácil de aprender e difícil de escrever de forma confusa
- Microserviços e DevOps: Docker, Kubernetes e grande parte do ecossistema cloud são em Go
- CLI tools simples: Go produz binários estáticos rapidamente sem complexidade
- O projeto precisa de concorrência simples: goroutines são mais acessíveis que async Rust
- Onboarding rápido: novos membros da equipe ficam produtivos em dias, não semanas
Ecossistema e Comunidade
Go tem a vantagem de ser apoiada pelo Google e ter um ecossistema maduro para cloud e DevOps. Ferramentas como Docker, Kubernetes, Terraform e Prometheus são escritas em Go.
Rust, por outro lado, vem crescendo rapidamente. Empresas como AWS, Microsoft, Google, Meta e Cloudflare usam Rust em produção. O ecossistema de crates (pacotes) no crates.io já ultrapassou 150.000 bibliotecas, e a comunidade é consistentemente votada como a mais acolhedora no Stack Overflow Developer Survey.
Combinando Rust e Go
Uma abordagem cada vez mais comum é usar ambas as linguagens no mesmo projeto:
- Go para orquestração, APIs e lógica de negócios
- Rust para componentes de alta performance via FFI ou como serviços separados
Projetos como TiKV (banco de dados distribuído) e Firecracker (microVMs da AWS) demonstram como Rust brilha nos componentes críticos de performance.
Conclusão e Recomendação
Se você está começando um novo projeto em 2026, nossa recomendação é:
Para a maioria dos projetos web e microserviços, Go ainda é a escolha mais pragmática. A curva de aprendizado é menor, a velocidade de desenvolvimento é maior e o ecossistema cloud-native é imbatível.
Para projetos onde performance, segurança de memória ou controle de recursos são prioridade, Rust é a melhor escolha. O investimento na curva de aprendizado se paga com código mais robusto, menor consumo de recursos e menos bugs em produção.
Se a sua equipe já conhece Go e precisa de mais performance em componentes específicos, considere adotar Rust gradualmente nesses pontos críticos ao invés de reescrever tudo.
Veja Também
- Tutorial de Concorrência em Rust — Aprenda async/await, threads e canais em Rust
- Receita: Async/Await Básico — Exemplo prático de código assíncrono
- Rust vs C++: Segurança sem Sacrificar Performance — Compare Rust com outra linguagem de sistemas
- Rust vs Python: Quando Usar Cada Um — Se você vem do mundo Python
- Tutorial: API REST com Axum — Construa sua primeira API em Rust
- Instalação do Rust — Configure seu ambiente de desenvolvimento