---
title: "Rust para Programadores Python: Transição | Rust Brasil"
url: "https://rustlang.com.br/blog/rust-para-programadores-python/"
markdown_url: "https://rustlang.com.br/blog/rust-para-programadores-python.MD"
description: "Guia de transição de Python para Rust: comparações de sintaxe, conceitos e ferramentas lado a lado. Para devs Python."
date: "2026-02-17"
author: "Equipe Rust Brasil"
---

# Rust para Programadores Python: Transição | Rust Brasil

Guia de transição de Python para Rust: comparações de sintaxe, conceitos e ferramentas lado a lado. Para devs Python.


Se você vem do mundo Python e quer aprender Rust, este guia foi feito para você. Vamos mapear os conceitos que você já conhece em Python para seus equivalentes em Rust, com exemplos práticos e comparações diretas. Ao final, você terá uma base sólida para começar a escrever código Rust com confiança.

## Variáveis: Tipagem Dinâmica vs Tipagem Estática

Python usa tipagem dinâmica -- você não precisa declarar tipos. Rust usa tipagem estática com inferência de tipos.

| Conceito | Python | Rust |
|---|---|---|
| Declaração de variável | `x = 10` | `let x = 10;` |
| Variável mutável | `x = 10; x = 20` | `let mut x = 10; x = 20;` |
| Constante | `PI = 3.14` (convenção) | `const PI: f64 = 3.14;` |
| Anotação de tipo | `x: int = 10` (opcional) | `let x: i32 = 10;` |

**Python:**
```python
nome = "Maria"
idade = 30
idade = 31        # reatribuição normal
nome = 42         # Python permite mudar o tipo
```

**Rust:**
```rust
let nome = "Maria";      // imutável por padrão
let mut idade = 30;       // mutável, permite reatribuição
idade = 31;               // ok, mesmo tipo
// idade = "trinta";      // ERRO: tipos incompatíveis
```

Em Rust, variáveis são imutáveis por padrão. Para permitir reatribuição, use `mut`. Além disso, Rust possui o conceito de *shadowing*, que permite redeclarar uma variável com o mesmo nome:

```rust
let x = 5;
let x = x + 1;    // shadowing: novo binding, pode mudar o tipo
let x = "texto";   // válido com shadowing
```

## Strings: `str` vs `String` e `&str`

Python tem um único tipo `str`. Rust diferencia entre `String` (alocada no heap, mutável) e `&str` (referência a uma fatia de string, imutável).

| Operação | Python | Rust |
|---|---|---|
| Criar string | `s = "olá"` | `let s = String::from("olá");` |
| String literal | `s = "olá"` | `let s: &str = "olá";` |
| Concatenar | `s1 + s2` | `format!("{}{}", s1, s2)` |
| Tamanho | `len(s)` | `s.len()` |
| Fatiar | `s[1:3]` | `&s[1..3]` |
| Maiúsculas | `s.upper()` | `s.to_uppercase()` |
| Contém | `"ol" in s` | `s.contains("ol")` |

**Python:**
```python
nome = "Rust"
saudacao = f"Olá, {nome}! Bem-vindo ao Brasil."
partes = saudacao.split(" ")
```

**Rust:**
```rust
let nome = "Rust";
let saudacao = format!("Olá, {}! Bem-vindo ao Brasil.", nome);
let partes: Vec<&str> = saudacao.split(" ").collect();
```

## Listas vs `Vec<T>`

O equivalente mais próximo da lista Python em Rust é o `Vec<T>`, mas com tipo homogêneo.

| Operação | Python | Rust |
|---|---|---|
| Criar | `nums = [1, 2, 3]` | `let nums = vec![1, 2, 3];` |
| Adicionar | `nums.append(4)` | `nums.push(4);` |
| Acessar | `nums[0]` | `nums[0]` |
| Tamanho | `len(nums)` | `nums.len()` |
| Fatiar | `nums[1:3]` | `&nums[1..3]` |
| Iterar | `for n in nums:` | `for n in &nums {` |
| Remover último | `nums.pop()` | `nums.pop()` |

**Python:**
```python
frutas = ["maçã", "banana", "laranja"]
frutas.append("uva")
for fruta in frutas:
    print(fruta)
```

**Rust:**
```rust
let mut frutas = vec!["maçã", "banana", "laranja"];
frutas.push("uva");
for fruta in &frutas {
    println!("{}", fruta);
}
```

## Dicionários vs `HashMap<K, V>`

O `dict` do Python corresponde ao `HashMap` em Rust.

**Python:**
```python
capitais = {
    "Brasil": "Brasília",
    "Argentina": "Buenos Aires",
    "Chile": "Santiago",
}
capitais["Uruguai"] = "Montevidéu"

for pais, capital in capitais.items():
    print(f"{pais}: {capital}")

capital = capitais.get("Peru", "Desconhecida")
```

**Rust:**
```rust
use std::collections::HashMap;

let mut capitais = HashMap::new();
capitais.insert("Brasil", "Brasília");
capitais.insert("Argentina", "Buenos Aires");
capitais.insert("Chile", "Santiago");
capitais.insert("Uruguai", "Montevidéu");

for (pais, capital) in &capitais {
    println!("{}: {}", pais, capital);
}

let capital = capitais.get("Peru").unwrap_or(&"Desconhecida");
```

## `None` vs `Option<T>`

Python usa `None` para representar ausência de valor. Rust usa o enum `Option<T>`, que força o tratamento explícito.

**Python:**
```python
def buscar_usuario(id: int) -> dict | None:
    if id == 1:
        return {"nome": "Ana"}
    return None

usuario = buscar_usuario(1)
if usuario is not None:
    print(usuario["nome"])
```

**Rust:**
```rust
fn buscar_usuario(id: u32) -> Option<String> {
    if id == 1 {
        Some(String::from("Ana"))
    } else {
        None
    }
}

// Tratamento com match
match buscar_usuario(1) {
    Some(nome) => println!("{}", nome),
    None => println!("Usuário não encontrado"),
}

// Ou com if let
if let Some(nome) = buscar_usuario(1) {
    println!("{}", nome);
}
```

## Exceções vs `Result<T, E>`

Python usa exceções com `try/except`. Rust usa o tipo `Result<T, E>` e o operador `?`.

**Python:**
```python
def ler_arquivo(caminho: str) -> str:
    try:
        with open(caminho, "r") as f:
            return f.read()
    except FileNotFoundError:
        return "Arquivo não encontrado"
    except PermissionError:
        return "Sem permissão"
```

**Rust:**
```rust
use std::fs;
use std::io;

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

// Uso com match
match ler_arquivo("dados.txt") {
    Ok(conteudo) => println!("{}", conteudo),
    Err(e) => eprintln!("Erro: {}", e),
}

// Ou propagando o erro com ?
fn processar() -> Result<(), io::Error> {
    let conteudo = ler_arquivo("dados.txt")?;
    println!("{}", conteudo);
    Ok(())
}
```

O operador `?` em Rust é equivalente a deixar a exceção propagar em Python -- mas de forma explícita e verificada em tempo de compilação.

## Classes vs Structs + `impl` + Traits

Python usa classes com herança. Rust usa structs, blocos `impl` e traits.

**Python:**
```python
class Animal:
    def __init__(self, nome: str, peso: float):
        self.nome = nome
        self.peso = peso

    def falar(self) -> str:
        return f"{self.nome} faz um som"

    def __str__(self) -> str:
        return f"Animal({self.nome}, {self.peso}kg)"

class Cachorro(Animal):
    def falar(self) -> str:
        return f"{self.nome} late: Au au!"
```

**Rust:**
```rust
struct Animal {
    nome: String,
    peso: f64,
}

trait Falante {
    fn falar(&self) -> String;
}

impl Animal {
    fn new(nome: &str, peso: f64) -> Self {
        Animal {
            nome: nome.to_string(),
            peso,
        }
    }
}

impl std::fmt::Display for Animal {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "Animal({}, {}kg)", self.nome, self.peso)
    }
}

impl Falante for Animal {
    fn falar(&self) -> String {
        format!("{} faz um som", self.nome)
    }
}

struct Cachorro {
    animal: Animal,
}

impl Falante for Cachorro {
    fn falar(&self) -> String {
        format!("{} late: Au au!", self.animal.nome)
    }
}
```

Rust não tem herança. Em vez disso, usa composição e traits para polimorfismo. Traits definem comportamentos compartilhados, semelhante a interfaces ou protocolos.

## `pip` vs Cargo

| Tarefa | Python | Rust |
|---|---|---|
| Gerenciador de pacotes | `pip` | `cargo` |
| Arquivo de dependências | `requirements.txt` / `pyproject.toml` | `Cargo.toml` |
| Instalar dependências | `pip install -r requirements.txt` | `cargo build` |
| Adicionar pacote | `pip install requests` | `cargo add reqwest` |
| Executar projeto | `python main.py` | `cargo run` |
| Executar testes | `pytest` | `cargo test` |
| Criar novo projeto | -- | `cargo new meu_projeto` |
| Repositório de pacotes | PyPI | crates.io |

## `virtualenv` vs Cargo Workspaces

Python usa ambientes virtuais para isolar dependências. Em Rust, cada projeto tem seu próprio `Cargo.toml` e as dependências são gerenciadas por projeto automaticamente. Para monorepos, Rust oferece workspaces:

**Python:**
```bash
python -m venv .venv
source .venv/bin/activate
pip install flask requests
```

**Rust (Cargo.toml de workspace):**
```toml
[workspace]
members = [
    "api",
    "core",
    "utils",
]
```

Cada membro do workspace tem seu próprio `Cargo.toml`, mas compartilham um diretório `target/` e um `Cargo.lock`.

## List Comprehensions vs Iteradores

As list comprehensions do Python mapeiam diretamente para a API de iteradores do Rust.

**Python:**
```python
# Filtrar e transformar
numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
pares_dobro = [n * 2 for n in numeros if n % 2 == 0]
# [4, 8, 12, 16, 20]

# Achatar listas
matriz = [[1, 2], [3, 4], [5, 6]]
plano = [x for linha in matriz for x in linha]
# [1, 2, 3, 4, 5, 6]

# Dicionário comprehension
quadrados = {n: n**2 for n in range(1, 6)}
```

**Rust:**
```rust
// Filtrar e transformar
let numeros = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let pares_dobro: Vec<i32> = numeros.iter()
    .filter(|&n| n % 2 == 0)
    .map(|n| n * 2)
    .collect();
// [4, 8, 12, 16, 20]

// Achatar vetores
let matriz = vec![vec![1, 2], vec![3, 4], vec![5, 6]];
let plano: Vec<i32> = matriz.into_iter()
    .flatten()
    .collect();
// [1, 2, 3, 4, 5, 6]

// HashMap a partir de iterador
use std::collections::HashMap;
let quadrados: HashMap<i32, i32> = (1..=5)
    .map(|n| (n, n.pow(2)))
    .collect();
```

Os iteradores de Rust são *lazy* (avaliação preguiçosa) e altamente otimizados -- muitas vezes tão rápidos quanto loops escritos manualmente.

## Decoradores vs Macros

Decoradores em Python e macros de atributo em Rust servem a propósitos semelhantes: modificar ou estender o comportamento de funções e structs.

**Python:**
```python
import time

def medir_tempo(func):
    def wrapper(*args, **kwargs):
        inicio = time.time()
        resultado = func(*args, **kwargs)
        fim = time.time()
        print(f"{func.__name__} levou {fim - inicio:.2f}s")
        return resultado
    return wrapper

@medir_tempo
def processar_dados():
    time.sleep(1)
    return "pronto"
```

**Rust:**
```rust
// Macros deriváveis (derive macros) - as mais comuns
#[derive(Debug, Clone, PartialEq)]
struct Ponto {
    x: f64,
    y: f64,
}

// Macros de atributo com bibliotecas como serde
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct Usuario {
    nome: String,
    email: String,
}

// Macro simples para medir tempo
macro_rules! medir_tempo {
    ($nome:expr, $bloco:block) => {{
        let inicio = std::time::Instant::now();
        let resultado = $bloco;
        let duracao = inicio.elapsed();
        println!("{} levou {:?}", $nome, duracao);
        resultado
    }};
}

// Uso
let resultado = medir_tempo!("processar_dados", {
    std::thread::sleep(std::time::Duration::from_secs(1));
    "pronto"
});
```

## Exemplo Completo: API REST

Para finalizar, vamos comparar um servidor HTTP simples nas duas linguagens.

**Python (Flask):**
```python
from flask import Flask, jsonify, request

app = Flask(__name__)
tarefas = []

@app.route("/tarefas", methods=["GET"])
def listar_tarefas():
    return jsonify(tarefas)

@app.route("/tarefas", methods=["POST"])
def criar_tarefa():
    tarefa = request.get_json()
    tarefas.append(tarefa)
    return jsonify(tarefa), 201

if __name__ == "__main__":
    app.run(port=8080)
```

**Rust (Actix-web):**
```rust
use actix_web::{web, App, HttpServer, HttpResponse};
use serde::{Deserialize, Serialize};
use std::sync::Mutex;

#[derive(Serialize, Deserialize, Clone)]
struct Tarefa {
    titulo: String,
    concluida: bool,
}

struct Estado {
    tarefas: Mutex<Vec<Tarefa>>,
}

async fn listar_tarefas(data: web::Data<Estado>) -> HttpResponse {
    let tarefas = data.tarefas.lock().unwrap();
    HttpResponse::Ok().json(tarefas.clone())
}

async fn criar_tarefa(
    data: web::Data<Estado>,
    tarefa: web::Json<Tarefa>,
) -> HttpResponse {
    let mut tarefas = data.tarefas.lock().unwrap();
    tarefas.push(tarefa.into_inner());
    HttpResponse::Created().finish()
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let estado = web::Data::new(Estado {
        tarefas: Mutex::new(Vec::new()),
    });

    HttpServer::new(move || {
        App::new()
            .app_data(estado.clone())
            .route("/tarefas", web::get().to(listar_tarefas))
            .route("/tarefas", web::post().to(criar_tarefa))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}
```

## Conclusão

A transição de Python para Rust exige uma mudança de mentalidade: do dinamismo e flexibilidade para segurança e desempenho em tempo de compilação. Os conceitos centrais se traduzem bem entre as duas linguagens, mas Rust exige que você seja explícito sobre propriedade de memória, mutabilidade e tratamento de erros.

**Dicas para a transição:**

1. **Comece pequeno** -- reescreva scripts simples em Rust antes de projetos grandes.
2. **Abrace o compilador** -- as mensagens de erro do Rust são excelentes e guiam você para o código correto.
3. **Pense em ownership** -- esse é o conceito mais novo para quem vem de Python. Dedique tempo para entender borrow checker.
4. **Use `cargo clippy`** -- é como um linter avançado que ensina Rust idiomático.
5. **Consulte a documentação** -- `cargo doc --open` gera documentação local de todas as suas dependências.

Bem-vindo ao Rust! A curva de aprendizado é real, mas os ganhos em segurança e desempenho valem o esforço.

Se você quer continuar aprofundando seus conhecimentos em Python enquanto aprende Rust, visite o [Python Brasil](https://python.dev.br) — nosso portal irmão com tutoriais, glossário e carreira Python em português.
