Plano de Estudos Rust: Nível Júnior (0-6 Meses)

Roadmap completo para sair do zero e se tornar um desenvolvedor Rust júnior em 6 meses. Mês a mês, com recursos, projetos práticos e checklist de habilidades para conseguir sua primeira vaga.

Aprender Rust pode parecer intimidador no início, mas com um plano estruturado e dedicação consistente, é perfeitamente possível atingir o nível júnior em cerca de seis meses. Este guia foi criado especificamente para quem está começando do zero ou migrando de outra linguagem e quer construir uma base sólida o suficiente para conquistar sua primeira vaga profissional com Rust.

O plano pressupõe uma dedicação média de 1 a 2 horas por dia durante a semana e 3 a 4 horas nos finais de semana. Se você tiver mais disponibilidade, pode acelerar; se tiver menos, estenda o cronograma proporcionalmente. O importante é manter a consistência.

Visão Geral do Roadmap

Aqui está a visão macro dos seis meses de estudo:

MêsFoco PrincipalResultado Esperado
1Fundamentos da linguagemEscrever programas simples com confiança
2Ownership, borrowing e tipos compostosEntender o modelo de memória do Rust
3Tratamento de erros, coleções e traitsEscrever código idiomático e robusto
4Módulos, crates, testes e documentaçãoEstruturar projetos profissionais
5Projeto 1 – Ferramenta CLI completaTer um projeto real no portfólio
6Projeto 2 – API Web + CandidaturasEstar pronto para o mercado

Mês 1: Fundamentos do Rust

O primeiro mês é dedicado a absorver os conceitos básicos da linguagem. Não se preocupe em entender tudo profundamente agora. O objetivo é ganhar fluência na sintaxe e nos conceitos fundamentais.

Semana 1: Ambiente e Primeiros Passos

Objetivos:

  • Instalar Rust via rustup
  • Configurar seu editor (VS Code + rust-analyzer recomendado)
  • Entender o ciclo compile-run
  • Escrever seu primeiro “Hello, World!”

Conteúdo para estudar:

  • Capítulos 1 e 2 do “The Rust Book” (O Livro)
  • Instalar e configurar rust-analyzer
  • Aprender os comandos básicos do cargo: new, build, run, check
fn main() {
    println!("Olá, mundo Rust!");

    // Experimente modificar e recompilar
    let nome = "Rustacean";
    println!("Bem-vindo(a), {}!", nome);
}

Exercícios práticos:

  • Complete os 10 primeiros exercícios do Rustlings
  • Crie 3 programas simples que usem println! com formatação
  • Explore a documentação com cargo doc --open

Semana 2: Variáveis, Tipos e Funções

Objetivos:

  • Entender variáveis mutáveis e imutáveis
  • Dominar os tipos primitivos (inteiros, floats, bool, char)
  • Escrever funções com parâmetros e retorno
  • Usar expressões vs. statements
fn calcular_imc(peso: f64, altura: f64) -> f64 {
    peso / (altura * altura) // expressão - sem ponto-e-vírgula
}

fn classificar_imc(imc: f64) -> &'static str {
    if imc < 18.5 {
        "Abaixo do peso"
    } else if imc < 25.0 {
        "Peso normal"
    } else if imc < 30.0 {
        "Sobrepeso"
    } else {
        "Obesidade"
    }
}

fn main() {
    let peso = 75.0;
    let altura = 1.78;
    let imc = calcular_imc(peso, altura);

    println!("IMC: {:.1} - {}", imc, classificar_imc(imc));
}

Exercícios:

  • Crie uma calculadora que receba operação e operandos
  • Implemente uma função que converta Celsius para Fahrenheit
  • Escreva um programa que calcule juros compostos

Semana 3: Controle de Fluxo

Objetivos:

  • Dominar if/else, loop, while, for
  • Entender match como switch aprimorado
  • Usar ranges e iteração sobre coleções
fn fibonacci(n: u32) -> u64 {
    match n {
        0 => 0,
        1 => 1,
        _ => {
            let mut a: u64 = 0;
            let mut b: u64 = 1;
            for _ in 2..=n {
                let temp = b;
                b = a + b;
                a = temp;
            }
            b
        }
    }
}

fn main() {
    for i in 0..10 {
        println!("fibonacci({}) = {}", i, fibonacci(i));
    }
}

Exercícios:

  • Implemente FizzBuzz usando match
  • Crie um jogo de adivinhação de números (como no Livro, cap. 2)
  • Escreva um programa que encontre números primos até N

Semana 4: Strings e Dados Básicos

Objetivos:

  • Entender a diferença entre String e &str
  • Trabalhar com arrays, tuplas e slices
  • Praticar formatação de saída
fn contar_vogais(texto: &str) -> usize {
    texto.chars()
        .filter(|c| "aeiouáéíóúâêôãõ".contains(c.to_lowercase().next().unwrap()))
        .count()
}

fn inverter_palavras(frase: &str) -> String {
    frase.split_whitespace()
        .rev()
        .collect::<Vec<&str>>()
        .join(" ")
}

fn main() {
    let frase = String::from("Rust é incrível para sistemas");
    println!("Vogais: {}", contar_vogais(&frase));
    println!("Invertida: {}", inverter_palavras(&frase));
}

Checklist do Mês 1

  • Ambiente Rust instalado e configurado
  • Capítulos 1-3 do Rust Book lidos
  • 30+ exercícios do Rustlings completados
  • 5+ programas pequenos escritos do zero
  • Confortável com cargo build/run/check

Mês 2: Ownership, Borrowing e Tipos Compostos

Este é o mês mais importante e possivelmente o mais desafiador. O sistema de ownership é o coração do Rust, e entendê-lo bem agora vai evitar muitas frustrações depois.

Semana 5: Ownership e Move Semantics

Objetivos:

  • Entender as 3 regras do ownership
  • Compreender move semantics vs. copy
  • Saber quando usar clone() e quando evitar
fn main() {
    // Move semantics com String
    let s1 = String::from("Olá");
    let s2 = s1; // s1 foi movido para s2
    // println!("{}", s1); // ERRO: s1 não é mais válido
    println!("{}", s2);

    // Copy semantics com tipos primitivos
    let x = 42;
    let y = x; // x é copiado, não movido
    println!("x = {}, y = {}", x, y); // Funciona!

    // Passando ownership para função
    let nome = String::from("Brasil");
    imprimir(nome); // nome é movido para a função
    // println!("{}", nome); // ERRO: nome foi movido
}

fn imprimir(texto: String) {
    println!("{}", texto);
} // texto é dropped aqui

Semana 6: Borrowing e Referências

Objetivos:

  • Dominar referências imutáveis (&T) e mutáveis (&mut T)
  • Entender as regras do borrow checker
  • Saber resolver erros comuns de borrowing
fn adicionar_sobrenome(nome: &mut String, sobrenome: &str) {
    nome.push(' ');
    nome.push_str(sobrenome);
}

fn tamanho(texto: &str) -> usize {
    texto.len()
}

fn main() {
    let mut nome = String::from("Ferris");

    // Referência imutável - pode ter várias simultâneas
    let tam = tamanho(&nome);
    println!("Tamanho: {}", tam);

    // Referência mutável - apenas uma por vez
    adicionar_sobrenome(&mut nome, "the Crab");
    println!("Nome completo: {}", nome);
}

Semana 7: Structs e Implementações

Objetivos:

  • Definir e instanciar structs
  • Implementar métodos com impl
  • Entender struct update syntax e tuple structs
struct ContaBancaria {
    titular: String,
    saldo: f64,
    ativa: bool,
}

impl ContaBancaria {
    fn nova(titular: String) -> Self {
        ContaBancaria {
            titular,
            saldo: 0.0,
            ativa: true,
        }
    }

    fn depositar(&mut self, valor: f64) -> Result<f64, String> {
        if valor <= 0.0 {
            return Err("Valor deve ser positivo".to_string());
        }
        self.saldo += valor;
        Ok(self.saldo)
    }

    fn sacar(&mut self, valor: f64) -> Result<f64, String> {
        if valor <= 0.0 {
            return Err("Valor deve ser positivo".to_string());
        }
        if valor > self.saldo {
            return Err("Saldo insuficiente".to_string());
        }
        self.saldo -= valor;
        Ok(self.saldo)
    }

    fn extrato(&self) {
        println!("=== Extrato ===");
        println!("Titular: {}", self.titular);
        println!("Saldo: R$ {:.2}", self.saldo);
        println!("Status: {}", if self.ativa { "Ativa" } else { "Inativa" });
    }
}

fn main() {
    let mut conta = ContaBancaria::nova("Maria Silva".to_string());
    conta.depositar(1500.0).unwrap();
    conta.sacar(350.0).unwrap();
    conta.extrato();
}

Semana 8: Enums e Pattern Matching

Objetivos:

  • Criar enums com dados associados
  • Dominar pattern matching com match
  • Usar Option<T> e entender a ausência de null
enum Forma {
    Circulo(f64),
    Retangulo(f64, f64),
    Triangulo(f64, f64, f64),
}

impl Forma {
    fn area(&self) -> f64 {
        match self {
            Forma::Circulo(raio) => std::f64::consts::PI * raio * raio,
            Forma::Retangulo(largura, altura) => largura * altura,
            Forma::Triangulo(a, b, c) => {
                let s = (a + b + c) / 2.0;
                (s * (s - a) * (s - b) * (s - c)).sqrt()
            }
        }
    }

    fn descricao(&self) -> String {
        match self {
            Forma::Circulo(r) => format!("Círculo com raio {:.1}", r),
            Forma::Retangulo(l, a) => format!("Retângulo {}x{}", l, a),
            Forma::Triangulo(a, b, c) => format!("Triângulo ({}, {}, {})", a, b, c),
        }
    }
}

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

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

Checklist do Mês 2

  • Capítulos 4-6 do Rust Book lidos
  • Consegue explicar ownership, borrowing e lifetimes para outra pessoa
  • Resolve erros do borrow checker sem desespero
  • Cria structs com métodos e implementações
  • Usa enums com dados associados e pattern matching

Mês 3: Tratamento de Erros, Coleções e Traits

Agora que você domina a base, é hora de aprender a escrever código robusto e idiomático.

Semana 9: Tratamento de Erros

Objetivos:

  • Dominar Result<T, E> e Option<T>
  • Usar o operador ? para propagação de erros
  • Criar tipos de erro personalizados
use std::fs;
use std::num::ParseIntError;

#[derive(Debug)]
enum AppError {
    ArquivoNaoEncontrado(String),
    ParseErro(ParseIntError),
    ValorInvalido(String),
}

impl std::fmt::Display for AppError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            AppError::ArquivoNaoEncontrado(nome) => {
                write!(f, "Arquivo não encontrado: {}", nome)
            }
            AppError::ParseErro(e) => write!(f, "Erro ao converter: {}", e),
            AppError::ValorInvalido(msg) => write!(f, "Valor inválido: {}", msg),
        }
    }
}

impl From<ParseIntError> for AppError {
    fn from(e: ParseIntError) -> Self {
        AppError::ParseErro(e)
    }
}

fn ler_numero_do_arquivo(caminho: &str) -> Result<i32, AppError> {
    let conteudo = fs::read_to_string(caminho)
        .map_err(|_| AppError::ArquivoNaoEncontrado(caminho.to_string()))?;

    let numero: i32 = conteudo.trim().parse()?;

    if numero < 0 {
        return Err(AppError::ValorInvalido(
            "Número deve ser positivo".to_string(),
        ));
    }

    Ok(numero)
}

Semana 10: Coleções e Iteradores

Objetivos:

  • Dominar Vec<T>, HashMap<K, V>, HashSet<T>
  • Entender o padrão de iteradores (map, filter, fold, collect)
  • Usar closures com iteradores
use std::collections::HashMap;

fn analise_de_texto(texto: &str) -> HashMap<String, usize> {
    let mut contagem: HashMap<String, usize> = HashMap::new();

    for palavra in texto.split_whitespace() {
        let palavra_limpa = palavra
            .to_lowercase()
            .chars()
            .filter(|c| c.is_alphabetic())
            .collect::<String>();

        if !palavra_limpa.is_empty() {
            *contagem.entry(palavra_limpa).or_insert(0) += 1;
        }
    }

    contagem
}

fn top_palavras(contagem: &HashMap<String, usize>, n: usize) -> Vec<(&String, &usize)> {
    let mut pares: Vec<_> = contagem.iter().collect();
    pares.sort_by(|a, b| b.1.cmp(a.1));
    pares.into_iter().take(n).collect()
}

fn main() {
    let texto = "Rust é seguro. Rust é rápido. Rust é incrível. \
                 Aprender Rust vale a pena.";

    let contagem = analise_de_texto(texto);

    println!("Top 5 palavras:");
    for (palavra, freq) in top_palavras(&contagem, 5) {
        println!("  {}: {} vezes", palavra, freq);
    }

    // Exemplo com iteradores encadeados
    let numeros = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    let soma_pares: i32 = numeros
        .iter()
        .filter(|&&n| n % 2 == 0)
        .map(|&n| n * n)
        .sum();

    println!("Soma dos quadrados dos pares: {}", soma_pares);
}

Semana 11: Traits

Objetivos:

  • Definir e implementar traits
  • Usar traits como parâmetros (trait bounds)
  • Implementar traits da biblioteca padrão (Display, Debug, Clone)
use std::fmt;

trait Resumivel {
    fn resumo(&self) -> String;

    fn tipo(&self) -> &str {
        "Conteúdo genérico" // implementação padrão
    }
}

struct Artigo {
    titulo: String,
    autor: String,
    conteudo: String,
}

struct Tweet {
    usuario: String,
    texto: String,
    curtidas: u32,
}

impl Resumivel for Artigo {
    fn resumo(&self) -> String {
        format!("{}, por {} - {}...", self.titulo, self.autor, &self.conteudo[..50.min(self.conteudo.len())])
    }

    fn tipo(&self) -> &str {
        "Artigo"
    }
}

impl Resumivel for Tweet {
    fn resumo(&self) -> String {
        format!("@{}: {} ({} curtidas)", self.usuario, self.texto, self.curtidas)
    }

    fn tipo(&self) -> &str {
        "Tweet"
    }
}

impl fmt::Display for Artigo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "[{}] {} por {}", self.tipo(), self.titulo, self.autor)
    }
}

fn imprimir_resumo(item: &impl Resumivel) {
    println!("[{}] {}", item.tipo(), item.resumo());
}

Semana 12: Lifetimes Básicas

Objetivos:

  • Entender por que lifetimes existem
  • Usar anotações de lifetime básicas
  • Entender lifetime elision rules
// O compilador precisa saber qual referência determina o lifetime do retorno
fn maior<'a>(s1: &'a str, s2: &'a str) -> &'a str {
    if s1.len() > s2.len() {
        s1
    } else {
        s2
    }
}

// Struct com lifetime - garante que a referência vive o suficiente
struct Trecho<'a> {
    texto: &'a str,
    linha: usize,
}

impl<'a> Trecho<'a> {
    fn novo(texto: &'a str, linha: usize) -> Self {
        Trecho { texto, linha }
    }

    fn exibir(&self) {
        println!("Linha {}: {}", self.linha, self.texto);
    }
}

fn main() {
    let texto1 = String::from("Rust");
    let resultado;
    {
        let texto2 = String::from("Ferrugem");
        resultado = maior(&texto1, &texto2);
        println!("Maior: {}", resultado);
    }
    // resultado não pode ser usado aqui se dependesse de texto2
}

Checklist do Mês 3

  • Capítulos 7-10 do Rust Book lidos
  • Sabe criar tipos de erro personalizados
  • Usa iteradores fluentemente (map, filter, collect, etc.)
  • Define e implementa traits própcias
  • Entende lifetimes básicas e sabe anotar quando necessário

Mês 4: Módulos, Crates, Testes e Documentação

Hora de aprender a estruturar projetos profissionais.

Semana 13: Módulos e Organização de Código

Objetivos:

  • Organizar código em módulos e submódulos
  • Entender visibilidade (pub, pub(crate))
  • Criar e usar crates externas
meu_projeto/
├── Cargo.toml
├── src/
│   ├── main.rs          // ponto de entrada
│   ├── lib.rs           // biblioteca pública
│   ├── config.rs        // módulo de configuração
│   ├── models/
│   │   ├── mod.rs       // declara submódulos
│   │   ├── usuario.rs
│   │   └── produto.rs
│   └── services/
│       ├── mod.rs
│       ├── auth.rs
│       └── database.rs
└── tests/
    └── integration_test.rs
// src/models/usuario.rs
pub struct Usuario {
    pub nome: String,
    pub email: String,
    senha_hash: String, // privado
}

impl Usuario {
    pub fn novo(nome: String, email: String, senha: &str) -> Self {
        Usuario {
            nome,
            email,
            senha_hash: format!("hash_{}", senha), // simplificado
        }
    }

    pub fn verificar_senha(&self, senha: &str) -> bool {
        self.senha_hash == format!("hash_{}", senha)
    }
}

Semana 14: Testes Unitários e de Integração

Objetivos:

  • Escrever testes unitários com #[test]
  • Usar assert!, assert_eq!, assert_ne!
  • Criar testes de integração
  • Testar código que retorna Result
pub fn dividir(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 {
        Err("Divisão por zero".to_string())
    } else {
        Ok(a / b)
    }
}

pub fn eh_palindromo(texto: &str) -> bool {
    let limpo: String = texto
        .to_lowercase()
        .chars()
        .filter(|c| c.is_alphanumeric())
        .collect();
    let reverso: String = limpo.chars().rev().collect();
    limpo == reverso
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn dividir_numeros_validos() {
        assert_eq!(dividir(10.0, 2.0).unwrap(), 5.0);
    }

    #[test]
    fn dividir_por_zero_retorna_erro() {
        assert!(dividir(10.0, 0.0).is_err());
    }

    #[test]
    fn palindromo_simples() {
        assert!(eh_palindromo("arara"));
        assert!(eh_palindromo("Ana"));
        assert!(!eh_palindromo("rust"));
    }

    #[test]
    fn palindromo_com_espacos() {
        assert!(eh_palindromo("A base do teto desaba"));
    }
}

Semana 15: Documentação e Cargo

Objetivos:

  • Escrever doc comments (/// e //!)
  • Gerar documentação com cargo doc
  • Configurar Cargo.toml corretamente
  • Usar features e dependências opcionais
//! # Minha Biblioteca de Utilidades
//!
//! Esta crate fornece funções utilitárias para manipulação
//! de texto e cálculos matemáticos.

/// Calcula a média de uma sequência de números.
///
/// # Argumentos
///
/// * `numeros` - Um slice de valores f64
///
/// # Retorno
///
/// Retorna `Some(media)` se o slice não estiver vazio,
/// ou `None` caso contrário.
///
/// # Exemplos
///
/// ```
/// let nums = vec![1.0, 2.0, 3.0, 4.0, 5.0];
/// let media = minha_lib::media(&nums);
/// assert_eq!(media, Some(3.0));
/// ```
pub fn media(numeros: &[f64]) -> Option<f64> {
    if numeros.is_empty() {
        return None;
    }
    Some(numeros.iter().sum::<f64>() / numeros.len() as f64)
}

Semana 16: Gerenciamento de Dependências e Ferramentas

Objetivos:

  • Adicionar e gerenciar dependências no Cargo.toml
  • Usar clippy para linting
  • Formatar código com rustfmt
  • Usar cargo bench para benchmarks simples
[package]
name = "meu-projeto"
version = "0.1.0"
edition = "2021"
authors = ["Seu Nome <email@exemplo.com>"]
description = "Descrição do meu projeto"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }
clap = { version = "4", features = ["derive"] }

[dev-dependencies]
assert_cmd = "2.0"
predicates = "3.0"

Checklist do Mês 4

  • Capítulos 11-14 do Rust Book lidos
  • Sabe organizar projeto em módulos
  • Escreve testes unitários e de integração
  • Documenta código com doc comments
  • Usa clippy e rustfmt regularmente

Mês 5: Projeto 1 – Ferramenta CLI Completa

Este mês inteiro é dedicado a construir seu primeiro projeto real. Uma ferramenta de linha de comando é perfeita para o portfólio porque demonstra habilidades práticas sem a complexidade de um framework web.

Ideia de Projeto: Gerenciador de Tarefas CLI

Construa um gerenciador de tarefas com as seguintes funcionalidades:

Funcionalidades mínimas:

  • Adicionar tarefas com título e prioridade
  • Listar tarefas (todas, pendentes, concluídas)
  • Marcar tarefas como concluídas
  • Remover tarefas
  • Salvar/carregar de um arquivo JSON
  • Filtrar por prioridade

Tecnologias sugeridas:

  • clap para parsing de argumentos
  • serde + serde_json para serialização
  • chrono para datas
  • colored para output colorido

Estrutura do Projeto

task-manager/
├── Cargo.toml
├── README.md
├── src/
│   ├── main.rs
│   ├── cli.rs       // definição dos comandos
│   ├── task.rs      // modelo de tarefa
│   ├── storage.rs   // persistência em JSON
│   └── display.rs   // formatação de saída
└── tests/
    └── integration.rs

Exemplo de Código Principal

use clap::{Parser, Subcommand};

#[derive(Parser)]
#[command(name = "tarefas")]
#[command(about = "Gerenciador de tarefas no terminal")]
struct Cli {
    #[command(subcommand)]
    comando: Comandos,
}

#[derive(Subcommand)]
enum Comandos {
    /// Adiciona uma nova tarefa
    Adicionar {
        /// Título da tarefa
        titulo: String,
        /// Prioridade (alta, media, baixa)
        #[arg(short, long, default_value = "media")]
        prioridade: String,
    },
    /// Lista todas as tarefas
    Listar {
        /// Filtrar por status (todas, pendentes, concluidas)
        #[arg(short, long, default_value = "todas")]
        filtro: String,
    },
    /// Marca uma tarefa como concluída
    Concluir {
        /// ID da tarefa
        id: usize,
    },
    /// Remove uma tarefa
    Remover {
        /// ID da tarefa
        id: usize,
    },
}

Cronograma do Projeto

SemanaAtividade
17Estrutura do projeto, modelos de dados, CLI básica
18Persistência em JSON, CRUD completo
19Filtros, formatação bonita, tratamento de erros
20Testes, documentação, README, polish final

Dicas Importantes

  1. Comece simples: faça funcionar primeiro, depois melhore
  2. Commits frequentes: faça commits pequenos e descritivos
  3. Testes desde o início: não deixe para o final
  4. README completo: inclua instalação, uso e exemplos
  5. Peça feedback: compartilhe na comunidade Rust Brasil

Mês 6: Projeto 2 – API Web + Preparação para Vagas

O último mês combina a construção de um segundo projeto (web) com a preparação ativa para candidaturas.

Projeto 2: API REST Simples

Construa uma API REST para um sistema de notas/anotações:

Funcionalidades:

  • CRUD de notas (criar, listar, buscar, atualizar, deletar)
  • Busca por texto
  • Tags e categorias
  • Paginação

Tecnologias sugeridas:

  • axum como framework web
  • sqlx com SQLite para persistência
  • serde para serialização JSON
  • tokio como runtime async
  • tower-http para middleware (CORS, logging)

Exemplo de Endpoint

use axum::{
    extract::{Path, State},
    http::StatusCode,
    routing::{get, post},
    Json, Router,
};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Clone)]
struct Nota {
    id: Option<i64>,
    titulo: String,
    conteudo: String,
    tags: Vec<String>,
}

async fn criar_nota(
    State(pool): State<sqlx::SqlitePool>,
    Json(nota): Json<Nota>,
) -> Result<(StatusCode, Json<Nota>), StatusCode> {
    let resultado = sqlx::query_as!(
        Nota,
        "INSERT INTO notas (titulo, conteudo) VALUES (?, ?) RETURNING *",
        nota.titulo,
        nota.conteudo,
    )
    .fetch_one(&pool)
    .await
    .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    Ok((StatusCode::CREATED, Json(resultado)))
}

Preparação para Vagas (Semanas 23-24)

Currículo:

  • Destaque os dois projetos do portfólio
  • Mencione contribuições open source (se tiver)
  • Liste as tecnologias Rust que domina
  • Inclua link do GitHub com projetos bem documentados

Onde buscar vagas:

  • LinkedIn (filtrar por “Rust developer”)
  • Comunidade Rust Brasil (Telegram/Discord)
  • Remote OK, We Work Remotely
  • Empresas que usam Rust (lista no site oficial)
  • Plataformas brasileiras: Gupy, Catho, GeekHunter

Preparação para entrevistas:

  • Revise ownership, borrowing e lifetimes
  • Pratique coding challenges no LeetCode (em Rust)
  • Estude perguntas comuns (veja nosso guia de entrevistas)
  • Faça mock interviews com amigos da comunidade

Recursos Recomendados por Fase

Fase 1 (Meses 1-2): Fundamentos

RecursoTipoCusto
The Rust Programming Language (O Livro)Livro onlineGratuito
RustlingsExercícios interativosGratuito
Rust by ExampleExemplos práticosGratuito
Exercism - Rust TrackExercícios com mentoriaGratuito
“Primeiros Passos com Rust” (YouTube BR)Vídeo-aulasGratuito

Fase 2 (Meses 3-4): Intermediário

RecursoTipoCusto
Programming Rust (O’Reilly)LivroPago
Rust in ActionLivroPago
Crust of Rust (Jon Gjengset)YouTubeGratuito
Rust Design PatternsLivro onlineGratuito
Exercism - Exercícios avançadosExercíciosGratuito

Fase 3 (Meses 5-6): Projetos

RecursoTipoCusto
Zero To Production In RustLivroPago
Documentação do AxumDocsGratuito
Documentação do ClapDocsGratuito
Awesome Rust (GitHub)Lista curadaGratuito
Comunidade Rust BrasilTelegram/DiscordGratuito

Checklist Final: Pronto para Vagas Júnior?

Antes de se candidatar, verifique se você domina estes tópicos:

Conhecimento Técnico

  • Variáveis, tipos, funções e controle de fluxo
  • Ownership, borrowing e lifetimes (conceitual e prático)
  • Structs, enums e pattern matching
  • Traits e generics básicos
  • Tratamento de erros com Result e Option
  • Coleções (Vec, HashMap, iteradores)
  • Módulos, crates e visibilidade
  • Testes unitários e de integração
  • Documentação de código
  • Uso básico de async/await (para o projeto web)

Portfólio

  • Pelo menos 2 projetos completos no GitHub
  • Projetos com README bem escrito
  • Código limpo e bem organizado
  • Testes automatizados nos projetos
  • Commits descritivos e organizados

Habilidades Complementares

  • Git e GitHub fluente
  • Linha de comando confortável
  • Noções de HTTP e REST APIs
  • SQL básico
  • Inglês para leitura técnica (mínimo)

Dicas Finais de Motivação

  1. Não compare seu progresso com o de outros. Cada pessoa tem seu ritmo e contexto.

  2. Erros do compilador são seus amigos. O compilador do Rust é famoso por suas mensagens de erro didáticas. Leia-as com atenção.

  3. A curva de aprendizado é real, mas temporária. Os primeiros 2 meses são os mais difíceis. Depois disso, a produtividade cresce exponencialmente.

  4. Participe da comunidade desde o dia 1. Faça perguntas, compartilhe suas conquistas, ajude quem está começando depois de você.

  5. Consistência vence intensidade. Estudar 1 hora por dia durante 6 meses é melhor que estudar 12 horas por dia durante 2 semanas e desistir.

  6. Celebre cada pequena vitória. Compilou sem erros? Entendeu lifetimes? Conseguiu usar iteradores? Cada passo conta.

Lembre-se: milhares de pessoas aprenderam Rust partindo do zero. Você também pode. A comunidade Rust é reconhecida mundialmente por ser acolhedora e prestativa. Use isso a seu favor.

Boa jornada, futuro(a) Rustacean!