Table of Contents
Programação de Sistemas com Rust 🦀
Domine a linguagem que está revolucionando a infraestrutura de software moderna, focando em segurança de memória, performance nativa e concorrência segura.
Objetivo do Curso
Metodologia: Aprendizado prático (Learn by doing) focado em fundamentos sólidos, seguido por aplicações reais em ferramentas de linha de comando (CLI) e serviços Web de alta performance.
🎯 O Que Você Vai Aprender
-
Segurança de Memória --- Entenda o revolucionário sistema de Ownership e Borrowing que elimina erros de memória sem precisar de um Garbage Collector. Ver Módulo 2
-
Performance Nativa --- Escreva código com a velocidade de C e C++, mas com as garantias de segurança de uma linguagem moderna e amigável. Ver Fundamentos
-
:material-sync-lock: Concorrência Sem Medo --- Desenvolva sistemas multithread robustos, onde o compilador impede data races e erros de concorrência antes mesmo de rodar. Ver Concorrência
-
Ecossistema Moderno --- Construa desde ferramentas CLI profissionais até APIs Web escaláveis e aplicações em WebAssembly de alto desempenho. Ver Projetos
📚 Jornada de Aprendizado (16 Aulas)
O curso é estruturado para levar você do zero ao desenvolvimento de sistemas complexos.
🧱 Módulo 1: Introdução e Fundamentos (Aulas 01-04)
- Aula 01 - Introdução ao Rust e Setup 🦀
- Aula 02 - Fundamentos da Linguagem 🧩
- Aula 03 - Controle de Fluxo 🔄
- Aula 04 - Funções e Organização 📦
🧠 Módulo 2: Gerenciamento de Memória (Aulas 05-08)
- Aula 05 - Ownership (Parte 1) 🧠
- Aula 06 - Borrowing e Referências 🤝
- Aula 07 - Strings e Coleções 🧵
- Aula 08 - Structs e Enums 🏗️
🧬 Módulo 3: Abstrações e Qualidade (Aulas 09-12)
- Aula 09 - Tratamento de Erros ⚠️
- Aula 10 - Generics e Traits 🧬
- Aula 11 - Programação Funcional 🚀
- Aula 12 - Testes e Documentação 🧪
⚡ Módulo 4: Especialização e Web (Aulas 13-16)
- Aula 13 - Concorrência Segura 🧵
- Aula 14 - Projeto CLI Profissional 💻
- Aula 15 - Rust para Web 🌐
- Aula 16 - Projeto Final e Tendências 🎓
Plano de Ensino: Programação de Sistemas com Rust 🦀
📖 Ementa
O curso aborda os fundamentos da linguagem Rust, o sistema de gerenciamento de memória (Ownership), abstrações de alto nível (Traits e Generics) e a construção de sistemas reais, incluindo ferramentas de linha de comando (CLI) e serviços Backend.
🎯 Objetivos
- Compreender a segurança de memória sem Garbage Collector.
- Desenvolver algoritmos eficientes e seguros com Rust.
- Implementar concorrência segura (Fearless Concurrency).
- Construir aplicações Backend modernas e escaláveis.
📅 Cronograma
| Semana | Tópico | Atividade |
|---|---|---|
| 01 | Intro e Setup | Instalação e Hello World |
| 02 | Fundamentos | Variáveis e Tipos |
| 03 | Controle de Fluxo | if, match, loops |
| 04 | Funções e Módulos | Organização de código |
| 05 | Ownership Parte 1 | Stack vs Heap |
| 06 | Borrowing e Refs | Empréstimos seguros |
| 07 | Strings e Coleções | Vec, HashMap |
| 08 | Structs e Enums | Modelagem de dados |
| 09 | Erros | Result e panic! |
| 10 | Generics/Traits | Abstração |
| 11 | Funcional | Closures e Iteradores |
| 12 | Qualidade | Testes e Docs |
| 13 | Concorrência | Threads e Canais |
| 14 | CLI | Projeto prático |
| 15 | Web | APIs com Actix |
| 16 | Final | Projeto Integrador |
🧪 Metodologia
- Aulas teóricas com suporte de slides em RevealJS.
- Exercícios práticos semanais (Básico, Intermediário e Desafio).
- Quizzes síncronos e assíncronos.
- Atividades de laboratório focadas em mini-projetos reais.
📚 Bibliografia Recomendada
- The Rust Programming Language (Klabnik & Nichols)
- Programming Rust (Blandy & Orendorff)
- Rust in Action (Tim McNamara)
Aulas
Aulas do Curso 📚
Acesse aqui todo o conteúdo teórico dividido em módulos de aprendizado.
-
Módulo 1: Fundamentos de Backend --- A base do desenvolvimento de APIs e Microsserviços.
-
Módulo 2: Manipulação de Dados --- Implementação robusta e persistência de dados.
-
Módulo 3: Segurança e Autenticação --- Protegendo sua API contra acessos não autorizados.
-
Módulo 4: Aplicações SPA (React) --- Criando o frontend moderno para consumir sua API.
Aula 01 - Introdução ao Rust e Setup do Ambiente 🦀
Objetivo
Objetivo: Compreender as motivações por trás da criação da linguagem Rust, compará-la com outras linguagens de sistema e configurar o ambiente de desenvolvimento.
1. O que é Rust? 🛡️
Rust é uma linguagem de programação multiparadigma, focada em segurança de memória, performance e concorrência segura. Criada por Graydon Hoare na Mozilla Research, ela foi projetada para resolver os problemas crônicos de gerenciamento de memória em C e C++.
Por que Rust?
- Segurança de Memória: O compilador garante que você não terá erros como segfaults ou buffer overflows.
- Performance: Velocidade comparável a C e C++, sem a sobrecarga de um Garbage Collector (GC).
- Concorrência: O sistema de tipos previne data races em tempo de compilação.
2. Comparativo: Rust vs Outras Linguagens ⚖️
| Característica | 🦀 Rust | 🏛️ C/C++ | 🐹 Go | 🐍 Python |
|---|---|---|---|---|
| Abstração | Alta | Baixa/Média | Média | Altíssima |
| Gerenciamento de Memória | Ownership (Seguro) | Manual (Inseguro) | Garbage Collector | Garbage Collector |
| Performance | Máxima | Máxima | Alta | Baixa |
| Segurança de Tipos | Fortíssima | Média | Forte | Dinâmica |
Evolução das Linguagens de Sistema
graph LR
A["C (1972)"] --> B["C++ (1985)"]
B --> C["Rust (2010)"]
D["Java (1995)"] -.-> C
E["Ada"] -.-> C
style C fill:#f96,stroke:#333,stroke-width:4px
3. Setup do Ambiente 🛠️
O Rust utiliza uma ferramenta chamada rustup para gerenciar versões da linguagem e ferramentas associadas.
Passos para Instalação
🪟 Windows
- Baixe o instalador
rustup-init.exeem rustup.rs. - Você precisará do Visual Studio C++ Build Tools instalado.
- No terminal, execute:
🐧 Linux/macOS
- Execute o comando no terminal:
4. O Ecossistema Rust 📦
Três ferramentas principais que você usará diariamente: 1. rustc: O compilador de Rust. 2. cargo: O gerenciador de pacotes e build system (O "canivete suíço"). 3. rustup: Instalador e gerenciador de versões.
5. Primeiro Programa: Olá, Mundo! 🚀
Vamos criar nosso primeiro código Rust manualmente para entender a base.
Usando o Cargo (Caminho Profissional)
$ cargo new hello_rust
$ cd hello_rust
$ cargo run
Compiling hello_rust v0.1.0
Finished dev [unoptimized + debuginfo] target(s) in 0.5s
Running `target/debug/hello_rust`
Olá, mundo!
6. Mini-Projeto: Dashboard de Versão 📊
Sua missão é validar sua instalação e criar seu primeiro repositório:
- Certifique-se de que
rustc --versionecargo --versionfuncionam. - Crie um novo projeto com
cargo new projeto_aula_01. - Altere a mensagem no
src/main.rs. - Execute com
cargo run.
7. Exercício de Fixação 🧠
Conceitos Chave
Rust não possui Garbage Collector. Isso significa que ele não precisa "pausar" seu programa para limpar a memória.
- Qual a principal diferença entre o gerenciamento de memória do Rust e do Java/C#?
- Para que serve o comando
cargo build? - O que acontece se você tentar compilar um código Rust que possui uma falha de segurança de memória?
Próxima Aula: Vamos explorar os Fundamentos da Linguagem (Variáveis e Tipos)! 🧩
Aula 02 - Fundamentos da Linguagem 🧩
Objetivo
Objetivo: Entender como o Rust lida com dados através de variáveis imutáveis por padrão, conhecer os tipos primitivos e aprender o conceito de shadowing.
1. Variáveis e Imutabilidade 🔒
Por padrão, todas as variáveis no Rust são imutáveis. Isso é uma escolha de design para garantir segurança e concorrência.
Imutável vs Mutável
fn main() {
let x = 5; // Imutável
// x = 6; // ERRO de compilação!
let mut y = 10; // Mutável (usando 'mut')
println!("y era: {}", y);
y = 15; // OK!
println!("y agora é: {}", y);
}
2. Tipos Primitivos 🧱
Rust é uma linguagem de tipagem estática, mas possui inferência de tipos.
Tipos Escalares
- Inteiros:
i8,u8,i32(padrão),u32,i64,u64,isize,usize. - Ponto Flutuante:
f32,f64(padrão). - Booleano:
bool(trueoufalse). - Caractere:
char(representa um valor Unicode de 4 bytes).
Tipos Compostos
- Tuplas: Agrupam vários valores de tipos diferentes.
- Arrays: Agrupam valores do mesmo tipo com tamanho fixo.
3. Constantes vs Variáveis 💎
Constantes são sempre imutáveis e seu tipo deve ser anotado explicitamente.
--- ## 4. Shadowing (Sombreamento) 👤
Shadowing permite declarar uma nova variável com o mesmo nome de uma anterior, "escondendo-a".
fn main() {
let x = 5;
let x = x + 1; // Shadowing
{
let x = x * 2;
println!("x interno: {}", x); // 12
}
println!("x externo: {}", x); // 6
}
Visualização de Escopo e Shadowing
graph TD
A["let x = 5"] --> B["let x = x + 1 (x=6)"]
B --> C["Escopo Interno"]
subgraph "Escopo Local"
C --> D["let x = x * 2 (x=12)"]
end
D --> E["Fim do Escopo"]
E --> F["x volta ao valor externo (x=6)"]
5. Mini-Projeto: Conversor de Temperatura 🌡️
Crie um programa que faça o seguinte:
1. Declare uma constante para o fator de conversão de Celsius para Fahrenheit.
2. Use variáveis mutáveis para armazenar o valor de entrada.
3. Utilize shadowing para transformar o resultado de f64 em uma mensagem formatada String.
4. Exiba o resultado no console.
6. Exercício de Fixação 🧠
Atenção
Tentar acessar um índice fora do array causará um panic em tempo de execução, mas o Rust verificará isso para você.
- Qual a palavra-chave usada para tornar uma variável mutável?
- Explique a diferença entre uma variável imutável e uma constante.
- O que acontece com a memória quando fazemos shadowing de uma variável?
Próxima Aula: Vamos controlar o fluxo do programa com Controle de Fluxo! 🔄
Aula 03 - Controle de Fluxo 🔄
Objetivo
Objetivo: Aprender a direcionar o caminho que o seu programa segue usando estruturas condicionais e de repetição, com foco especial no poder do match.
1. Condicionais: if / else 🚦
Diferente de C ou Java, o if no Rust é uma expressão, o que significa que ele pode retornar um valor.
fn main() {
let numero = 7;
if numero < 5 {
println!("Condição verdadeira");
} else {
println!("Condição falsa");
}
// Usando if em uma atribuição (Expressão)
let condicao = true;
let resultado = if condicao { 5 } else { 6 };
println!("O resultado é: {}", resultado);
}
2. O Poder do match 🎯
O match é como um switch "bombado". Ele é exaustivo: o compilador garante que você tratou todos os casos possíveis.
fn main() {
let numero = 3;
match numero {
1 => println!("Um"),
2 | 3 => println!("Dois ou Três"),
4..=10 => println!("Entre quatro e dez"),
_ => println!("Qualquer outra coisa"), // Default (padrão)
}
}
Visualização: Como o Match funciona
graph TD
A["Valor Entrada"] --> B{Qual Padrão?}
B -->|Padrão 1| C["Executa Código 1"]
B -->|Padrão 2| D["Executa Código 2"]
B -->|Padrão _| E["Caso Padrão (Catch-all)"]
style B fill:#f9f,stroke:#333,stroke-width:2px
3. Estruturas de Repetição (Loops) 🔁
Rust possui três tipos de loops: loop, while e for.
loop (Loop Infinito)
Útil para repetir até que um break seja encontrado. Pode retornar um valor!
let mut contador = 0;
let resultado = loop {
contador += 1;
if contador == 10 {
break contador * 2;
}
};
while (Loop Condicional)
for (Loop em Coleções ✨)
O mais utilizado por ser mais seguro e eficiente.
let a = [10, 20, 30, 40, 50];
for elemento in a {
println!("O valor é: {}", elemento);
}
// Usando Ranges
for numero in (1..4).rev() {
println!("{}...", numero);
}
4. Mini-Projeto: Jogo de Adivinhação (Base) 🎲
Vamos aplicar o que aprendemos para criar o núcleo de um jogo:
1. Gere um número "secreto" (fixo por enquanto).
2. Peça ao usuário uma entrada (simulada ou via stdin).
3. Use um loop para permitir várias tentativas.
4. Use um match para comparar o palpite com o número secreto (Menor, Maior ou Igual).
5. Use break para sair do loop quando ganhar.
5. Exercício de Fixação 🧠
Dica
Sempre prefira o for ao while quando estiver iterando sobre coleções para evitar erros de índice.
- Por que dizemos que o
ifé uma expressão no Rust? - O que acontece se você esquecer de tratar um caso no
match? - Como você faria um loop que conta de 1 a 100 (inclusive)?
Próxima Aula: Vamos organizar nosso código com Funções e Módulos! 📦
Aula 04 - Funções e Organização de Código 📦
Objetivo
Objetivo: Entender como declarar funções, passar parâmetros, retornar valores e como organizar o código em múltiplos arquivos e módulos para manter a manutenabilidade.
1. Funções em Rust 🛠️
No Rust, usamos a palavra-chave fn e a convenção de nomeação é o snake_case.
Anatomia de uma Função
fn main() {
println!("Início do programa");
outra_funcao(5, 'h');
}
fn outra_funcao(valor: i32, unidade: char) {
println!("O valor medido é: {}{}", valor, unidade);
}
2. Parâmetros e Retorno 🔄
Diferente de variáveis locais, você deve declarar o tipo de cada parâmetro em uma função.
Funções com Retorno
O tipo de retorno é declarado após a seta ->.
fn cinco() -> i32 {
5 // Sem ponto e vírgula = Retorno implícito
}
fn soma(a: i32, b: i32) -> i32 {
return a + b; // Uso opcional da palavra 'return'
}
3. Expressões vs Instruções 🧪
Rust é uma linguagem baseada em expressões.
- Instruções (Statements): Ações que não retornam valor (terminam em ;).
- Expressões (Expressions): Avaliam e resultam em um valor (não terminam em ;).
4. Organizando com Módulos 📂
Para projetos maiores, usamos o sistema de módulos (mod) para dividir o código.
Estrutura de Pastas
Usando Módulos em main.rs
Definindo em util.rs
5. Visualização: Hierarquia de Módulos 🏛️
graph TD
crate["Crate (Raiz)"] --> main["main.rs (Binário)"]
crate --> lib["lib.rs (Biblioteca)"]
main --> mod_auth["mod auth"]
main --> mod_db["mod db"]
mod_auth --> login["fn login()"]
mod_db --> query["fn query()"]
style crate fill:#f96,stroke:#333
6. Mini-Projeto: Calculadora Modular 🧮
Divida seu código em dois arquivos:
1. operacoes.rs: Contenha funções para somar, subtrair, multiplicar e dividir.
2. main.rs: Importe o módulo operacoes e realize uma série de cálculos baseados na entrada do usuário.
7. Exercício de Fixação 🧠
- Qual a diferença visual entre uma expressão e uma instrução no Rust?
- Para que serve a palavra-chave
pubantes de uma função em um módulo? - O que acontece se você declarar uma função que promete retornar um
i32mas não retorna nada?
Próxima Aula: Vamos encarar o conceito mais importante do Rust: Ownership (Parte 1)! 🧠 (Nota: O link correto será aula-05.md)
Aula 05 - Ownership (Parte 1) 🧠
Objetivo
Objetivo: Compreender o conceito de Ownership (Posse), a base da segurança de memória do Rust, e como ele gerencia dados sem a necessidade de um Garbage Collector.
1. Stack vs Heap 🏗️
Para entender o Ownership, precisamos saber onde os dados moram:
- Stack (Pilha): Rápida, tamanho fixo conhecido em tempo de compilação. Armazena tipos primitivos (
i32,bool, etc). - Heap (Monte): Mais lenta, tamanho dinâmico. Armazena dados complexos (
String,Vec).
2. As Três Regras de Ouro do Ownership 📜
Rust gerencia a memória através de um conjunto de regras que o compilador verifica:
- Cada valor em Rust tem uma variável que é chamada de seu owner (dono).
- Só pode haver um dono por vez.
- Quando o dono sai de escopo, o valor é descartado (Drop).
3. String: O Exemplo Perfeito 🧵
Diferente de literais de string ("oi"), o tipo String é alocado na Heap.
{
let s = String::from("olá"); // s é o dono da String
} // Aqui o escopo termina, e o Rust chama automaticamente a função 'drop' para limpar a memória.
4. Move vs Clone vs Copy 🔄
Move (Movimentação)
Quando atribuímos uma variável da Heap a outra, o Rust move o dono, invalidando a variável anterior. Isso evita o erro de "Double Free".
let s1 = String::from("texto");
let s2 = s1; // O dono agora é s2. s1 não é mais válido!
// println!("{}", s1); // ERRO de compilação!
Clone (Cópia Profunda)
Se quisermos copiar os dados da Heap, devemos usar explicitamente o método clone.
let s1 = String::from("texto");
let s2 = s1.clone(); // Cria uma nova cópia na Heap
println!("s1 = {}, s2 = {}", s1, s2); // OK!
Copy (Cópia da Stack)
Tipos com tamanho conhecido (como inteiros) são copiados automaticamente na Stack.
5. Visualização: O Conceito de Move 🚚
graph LR
subgraph "Antes"
s1_a[s1: dono] --> Data[("Dados na Heap: 'texto'")]
end
subgraph "Depois de let s2 = s1"
s1_b[s1: Inválido]
s2_b[s2: dono] --> Data
end
style s1_b fill:#f66,stroke:#333
6. Mini-Projeto: Gerenciador de Buffer 💾
Crie um programa que faça o seguinte:
1. Uma função que cria e retorna uma String (passando o Ownership para quem chama).
2. Uma função que recebe uma String por Ownership, adiciona um sufixo e a retorna de volta.
3. Demonstre o que acontece se você tentar usar uma variável após passá-la para uma função que não a retorna.
7. Exercício de Fixação 🧠
- O que acontece com a memória quando uma variável sai de escopo no Rust?
- Explique por que o Rust "move" os dados da Heap em vez de copiá-los por padrão.
- Qual a diferença entre
CopyeClone?
Próxima Aula: Vamos aprender a compartilhar dados sem mover o dono com Borrowing e Referências! 🤝
Aula 06 - Borrowing e Referências 🤝
Objetivo
Objetivo: Aprender a acessar dados sem obter sua posse (Ownership) através do conceito de Referências e Empréstimo (Borrowing).
1. O que são Referências? 🔍
Uma referência é como um ponteiro, mas com a garantia de que sempre apontará para um valor válido. Usamos o símbolo & para referenciar.
fn main() {
let s1 = String::from("texto");
let tam = calcular_tamanho(&s1); // Passamos uma referência, não a posse
println!("O tamanho de '{}' é {}.", s1, tam); // s1 ainda é válido!
}
fn calcular_tamanho(s: &String) -> usize {
s.len()
} // s sai de escopo, mas como é uma referência, nada é descartado na Heap.
2. Empréstimo Mutável ✍️
Por padrão, referências são imutáveis. Para mudar um valor emprestado, precisamos de uma referência mutável (&mut).
fn main() {
let mut s = String::from("olá");
mudar(&mut s);
}
fn mudar(valor: &mut String) {
valor.push_str(", mundo");
}
3. As Regras do Borrow Checker ⚖️
O Rust impõe duas regras fundamentais para evitar corridas de dados (data races):
- Você pode ter várias referências imutáveis (
&T) ao mesmo tempo. - Você pode ter apenas uma referência mutável (
&mut T) por vez. - Você não pode ter uma referência mutável se já houver uma imutável ativa.
let mut s = String::from("oi");
let r1 = &s; // OK
let r2 = &s; // OK
// let r3 = &mut s; // ERRO de compilação! (Já existem referências imutáveis)
4. Referências Pendentes (Dangling References) 🪢
O Rust impede que você crie referências que apontem para memória que já foi liberada.
// ERRO: s sai de escopo e é destruída, mas tentamos retornar uma referência a ela.
// fn dangling() -> &String {
// let s = String::from("oi");
// &s
// }
5. Visualização: Referências em Memória 🖼️
graph LR
subgraph Stack
r1[r1: &String]
end
subgraph Heap
Data[("String: 'texto'")]
end
r1 --> s1[s1: dono da String]
s1 --> Data
style r1 fill:#bbf,stroke:#333
6. Mini-Projeto: Editor de Texto Simples 📄
Crie um programa que:
1. Tenha uma String principal representando um documento.
2. Uma função exibir que recebe uma referência imutável e imprime o texto.
3. Uma função editar que recebe uma referência mutável e adiciona uma linha ao documento.
4. Tente (e veja falhar) chamar editar enquanto uma referência de exibir ainda estiver sendo usada.
7. Exercício de Fixação 🧠
Atenção
O escopo de uma referência começa onde ela é introduzida e termina na sua última utilização.
- Qual a diferença entre
&StringeStringem termos de Ownership? - Por que o Rust proíbe ter duas referências mutáveis ao mesmo tempo?
- Como o compilador sabe que uma referência é "pendente"?
Próxima Aula: Vamos trabalhar com textos e conjuntos de dados em Strings e Coleções! 🧵
Aula 07 - Strings e Coleções 🧵
Objetivo
Objetivo: Dominar as principais coleções de dados do Rust, entendendo a diferença entre os tipos de texto e como armazenar listas e mapas com eficiência.
1. O Mundo das Strings 🔤
No Rust, "string" geralmente se refere a dois tipos principais:
- String: Alocada na Heap, mutável, crescível. Você é o dono dela.
- &str (String Slice): Uma referência a uma sequência de caracteres UTF-8. Imutável.
Convertendo e Manipulando
let mut s = String::from("Olá"); // String
let slice: &str = " mundo"; // &str
s.push_str(slice); // Adiciona o slice à String
println!("{}", s);
2. Vetores: Vec<T> 📦
Um vetor permite armazenar mais de um valor em uma única estrutura de dados, um ao lado do outro na memória.
let mut v: Vec<i32> = Vec::new();
v.push(10);
v.push(20);
// Forma mais comum usando a macro vec!
let v2 = vec![1, 2, 3];
// Lendo elementos
match v.get(1) {
Some(valor) => println!("O segundo elemento é {}", valor),
None => println!("Não há segundo elemento."),
}
3. Mapas de Hash: HashMap<K, V> 🗺️
Armazena um mapeamento de chaves para valores. Útil para buscas rápidas.
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Azul"), 10);
scores.insert(String::from("Amarelo"), 50);
// Acessando valores
let time = String::from("Azul");
let score = scores.get(&time); // Retorna Option<&V>
4. Visualização: Como o Vetor cresce 📈
graph TD
subgraph "Capacidade = 2"
V1["Vetor [10, 20]"]
end
V1 -- push(30) --> V2["Nova Alocação (Cap=4)"]
subgraph "Capacidade = 4"
V2["Vetor [10, 20, 30, _ ]"]
end
style V2 fill:#dfd,stroke:#333
5. Mini-Projeto: Sistema de Inventário 🎒
Crie um programa que:
1. Use um HashMap para armazenar o nome de itens e suas quantidades.
2. Use um Vec para armazenar uma lista de logs de atividades (ex: "Adicionado 5 maçãs").
3. Permita ao usuário:
- Adicionar um item.
- Remover um item.
- Ver o inventário total e o histórico de logs.
6. Exercício de Fixação 🧠
Coleções
Lembre-se: Vetores e Mapas armazenam seus dados na Heap, o que permite que cresçam dinamicamente.
- Por que não podemos usar um literal de string (
"texto") quando precisamos mudar o conteúdo? - Qual a vantagem de usar
v.get(index)em vez dev[index]? - O que acontece se inserirmos uma chave que já existe em um
HashMap?
Próxima Aula: Vamos criar nossos próprios tipos complexos com Structs e Enums! 🏗️
Aula 08 - Structs e Enums 🏗️
Objetivo
Objetivo: Aprender a definir seus próprios tipos de dados complexos usando Structs e Enums, e entender como o Rust lida com a ausência de valores (null) de forma segura.
1. Structs: Estruturando Dados 🧱
Uma Struct permite agrupar valores relacionados em um único pacote nomeado.
struct Usuario {
ativo: bool,
nome: String,
email: String,
idade: u64,
}
fn main() {
let mut user1 = Usuario {
email: String::from("alguem@exemplo.com"),
nome: String::from("Ricardo"),
ativo: true,
idade: 30,
};
user1.email = String::from("novo@exemplo.com");
}
2. Métodos com impl ⚙️
Podemos definir funções que pertencem a uma Struct usando o bloco impl.
struct Retangulo {
largura: u32,
altura: u32,
}
impl Retangulo {
fn area(&self) -> u32 {
self.largura * self.altura
}
}
3. Enums: Tipos com Variantes 🌈
Enums permitem definir um tipo que pode ser uma de várias variantes.
enum Direcao {
Norte,
Sul,
Leste,
Oeste,
}
enum Mensagem {
Sair,
Mover { x: i32, y: i32 },
Escrever(String),
}
4. O Fim do "Null": Option<T> 🛡️
Rust não possui o valor null. Em seu lugar, usamos o Enum Option.
enum Option<T> {
None,
Some(T),
}
let algum_numero = Some(5);
let nenhum_numero: Option<i32> = None;
5. Visualização: Pattern Matching com Enums 🧩
graph TD
A["Valor Option<i32>"] --> B{Dá match?}
B -->|Some(n)| C["Usa o valor 'n'"]
B -->|None| D["Trata o caso vazio"]
style B fill:#f9f,stroke:#333
6. Mini-Projeto: Sistema de Gerenciamento de Tarefas 📝
Crie um programa que defina:
1. Uma Struct Tarefa com campos como titulo, descricao e status.
2. Um Enum Status com variantes: Pendente, EmAndamento, Concluida.
3. Implemente um método na Struct Tarefa para atualizar o status.
4. Use um Vec<Tarefa> para armazenar várias tarefas e um match para exibir mensagens diferentes dependendo do status de cada uma.
7. Exercício de Fixação 🧠
- Qual a diferença entre uma Struct e uma Tupla?
- Para que serve o parâmetro
&selfem um método? - Por que o uso de
Option<T>é considerado mais seguro que o uso denullem outras linguagens?
Próxima Aula: Vamos aprender a lidar com erros de forma profissional com Tratamento de Erros! ⚠️
Aula 09 - Tratamento de Erros ⚠️
Objetivo
Objetivo: Compreender a filosofia do Rust para lidar com falhas, diferenciando erros fatais de erros recuperáveis, e dominar o uso do tipo Result para um código robusto.
1. Erros Irrecuperáveis com panic! 💥
Um panic! indica que algo aconteceu que o programa não sabe como lidar. Quando ocorre, o programa imprime uma mensagem, limpa a memória (unwinding) e encerra.
fn main() {
// panic!("Algo deu muito errado!");
let v = vec![1, 2, 3];
v[99]; // Erro de índice causará um panic automático!
}
2. Erros Recuperáveis com Result<T, E> 🛡️
A maioria dos erros não são fatais. Para esses, o Rust usa o Enum Result.
Exemplo Prático: Abrindo um Arquivo
use std::fs::File;
fn main() {
let f = File::open("hello.txt");
let arquivo = match f {
Ok(file) => file,
Err(error) => panic!("Problema ao abrir o arquivo: {:?}", error),
};
}
3. Atalhos: unwrap e expect ⚡
Se você tem certeza que a operação terá sucesso ou quer que o programa dê panic em caso de erro, pode usar esses atalhos:
- unwrap(): Retorna o valor interno se for
Ok, caso contrário, chamapanic!. - expect("mensagem"): Similar ao unwrap, mas permite definir a mensagem de erro.
4. Propagação de Erros e o Operador ? 🚀
Em vez de tratar o erro na própria função, você pode "passá-lo adiante" para quem chamou a função usando o operador ?.
use std::fs::File;
use std::io::{self, Read};
fn ler_usuario_de_arquivo() -> Result<String, io::Error> {
let mut s = String::new();
File::open("hello.txt")?.read_to_string(&mut s)?; // O ? retorna o erro automaticamente se ocorrer
Ok(s)
}
5. Visualização: Fluxo do Operador ? 🔄
graph LR
A["Chamada da Função"] --> B{Deu erro?}
B -->|Não| C["Continua Execução"]
B -->|Sim| D["Retorna Err(e) Imediatamente"]
style B fill:#f96,stroke:#333
6. Mini-Projeto: Leitor de Configurações ⚙️
Desenvolva uma ferramenta que:
1. Tente ler um arquivo de configuração (ex: config.txt).
2. Se o arquivo não existir, crie um arquivo padrão com valores iniciais.
3. Use Result e o operador ? para gerenciar as falhas de leitura/escrita.
4. Trate erros de permissão ou arquivo corrompido de forma amigável para o usuário, sem travar o programa.
7. Exercício de Fixação 🧠
- Quando devemos usar
panic!em vez de retornar umResult? - O que o operador
?faz por baixo dos panos? - Por que o uso excessivo de
unwrap()é considerado uma má prática em código de produção?
Próxima Aula: Vamos aumentar a reutilização de código com Generics e Traits! 🧬
Aula 10 - Generics e Traits 🧬
Objetivo
Objetivo: Dominar o uso de Tipos Genéricos para criar código reutilizável e entender como as Traits (Traços) definem comportamentos compartilhados entre diferentes tipos.
1. Tipos Genéricos (Generics) 🧩
Generics permitem que as funções e estruturas trabalhem com múltiplos tipos sem duplicar código.
Em Funções
fn maior<T: PartialOrd>(lista: &[T]) -> &T {
let mut maior = &lista[0];
for item in lista {
if item > maior {
maior = item;
}
}
maior
}
Em Structs
struct Ponto<T> {
x: T,
y: T,
}
let p1 = Ponto { x: 5, y: 10 }; // Ponto de i32
let p2 = Ponto { x: 1.0, y: 4.0 }; // Ponto de f64
2. Traits: Definindo Comportamento 🛠️
Uma Trait diz ao compilador sobre a funcionalidade que um tipo específico possui e pode compartilhar com outros tipos. É similar a uma Interface em outras linguagens.
pub trait Resumo {
fn resumir(&self) -> String;
}
pub struct Artigo {
pub titulo: String,
pub autor: String,
}
impl Resumo for Artigo {
fn resumir(&self) -> String {
format!("{}: {}", self.titulo, self.autor)
}
}
3. Trait Bounds: Restringindo Generics ⛓️
Podemos usar Trait Bounds para especificar que um tipo genérico deve implementar uma determinada Trait.
4. Visualização: Polimorfismo com Traits 🎭
classDiagram
class Resumo {
<<interface>>
+resumir() String
}
class Artigo {
+titulo String
+resumir() String
}
class Tweet {
+username String
+resumir() String
}
Resumo <|.. Artigo
Resumo <|.. Tweet
5. Mini-Projeto: Sistema de Notificações 🔔
Desenvolva uma estrutura para um sistema de comunicação:
1. Defina uma Trait Notificavel com o método enviar(&self).
2. Crie Structs Email, SMS e WhatsApp.
3. Implemente a Trait Notificavel para cada uma delas (ex: o e-mail imprime "Enviando e-mail para...", etc).
4. Crie uma função genérica que receba uma lista de objetos que implementam Notificavel e chame o método enviar para todos.
6. Exercício de Fixação 🧠
- Qual a vantagem de usar Generics em vez de duplicar funções para cada tipo?
- O que acontece se chamarmos a função
maiorem um tipo que não implementa a comparação (PartialOrd)? - Podemos implementar uma Trait em um tipo que não criamos? (Ex:
impl MinhaTrait for i32). Justifique.
Próxima Aula: Vamos explorar o lado funcional do Rust com Programação Funcional: Closures e Iterators! 🚀
Aula 11 - Programação Funcional em Rust 🚀
Objetivo
Objetivo: Explorar os recursos de programação funcional do Rust que permitem escrever código mais limpo, expressivo e eficiente, focando em Closures e Iterators.
1. Closures: Funções Anônimas 🔒
Closures são funções anônimas que você pode armazenar em variáveis ou passar como argumentos para outras funções. Ao contrário das funções normais, elas podem capturar valores do escopo onde foram definidas.
fn main() {
let x = 4;
// Uma closure simples
let somar_x = |y| y + x;
println!("Resultado: {}", somar_x(2)); // 6
}
2. Iterators: Processando Sequências 🔄
O padrão Iterator permite realizar algumas tarefas em uma sequência de itens. Em Rust, iteradores são "preguiçosos" (lazy), o que significa que eles não fazem nada até que você chame métodos que os consumam.
let v1 = vec![1, 2, 3];
let v1_iter = v1.iter(); // Apenas cria o iterador
for val in v1_iter {
println!("Valor: {}", val);
}
3. Métodos Adaptadores: map, filter e collect 🧪
Estes métodos transformam um iterador em outro tipo de iterador ou em uma coleção.
- map: Transforma cada item.
- filter: Mantém apenas itens que satisfazem uma condição.
- collect: Transforma o iterador de volta em uma coleção (ex:
Vec).
let v1: Vec<i32> = vec![1, 2, 3];
let v2: Vec<_> = v1.iter()
.map(|x| x + 1)
.filter(|x| x % 2 == 0)
.collect();
println!("{:?}", v2); // [2, 4]
4. Abstrações de Custo Zero (Zero-Cost Abstractions) ⚡
Bjarne Stroustrup (criador do C++) definiu o termo que o Rust segue à risca: "O que você não usa, você não paga. E o que você usa, você não poderia escrever melhor à mão".
Isso significa que usar map e filter é tão rápido quanto escrever um loop for manual, pois o compilador otimiza tudo de forma agressiva.
5. Visualização: Pipeline de Dados ⛓️
graph LR
A["[1, 2, 3, 4]"] --> B["iter()"]
B --> C["filter(x > 2)"]
C --> D["map(x * 10)"]
D --> E["collect()"]
E --> F["[30, 40]"]
style B fill:#f96
style E fill:#f96
6. Mini-Projeto: Analisador de Logs 📊
Crie um sistema que:
1. Receba um Vec de Strings representando logs de um sistema (ex: "INFO: Login", "ERROR: Falha de Disco", "INFO: Logout").
2. Use iteradores para filtrar apenas os logs que contêm "ERROR".
3. Use map para extrair apenas a mensagem após o prefixo "ERROR: ".
4. Use collect para armazenar os resultados em um novo Vec.
5. Exiba a contagem total de erros encontrados.
7. Exercício de Fixação 🧠
- O que significa dizer que um iterador é "preguiçoso"?
- Qual a principal vantagem das Closures sobre funções comuns?
- Explique com suas palavras o conceito de "Abstração de Custo Zero".
Próxima Aula: Vamos profissionalizar nosso código com Testes e Documentação! 🧪
Aula 12 - Testes e Documentação 🧪
Objetivo
Objetivo: Profissionalizar o desenvolvimento em Rust aprendendo a escrever testes robustos e documentação automática que serve como ferramenta de especificação.
1. Testes Unitários: Garantindo a Qualidade 🛡️
O Rust possui ferramentas de teste integradas. Os testes unitários ficam no mesmo arquivo do código, em um módulo especial.
pub fn soma(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)] // Compila este módulo apenas ao rodar testes
mod tests {
use super::*; // Importa funções do arquivo pai
#[test]
fn test_soma() {
assert_eq!(soma(2, 2), 4);
}
}
Para rodar os testes:
2. Testes de Integração 🔗
Servem para testar sua biblioteca como um todo, como se você fosse um usuário externo. Ficam na pasta tests/ na raiz do projeto.
3. Documentação com rustdoc 📖
Rust usa comentários especiais (///) para gerar documentação HTML rica automaticamente.
/// Adiciona dois números e retorna a soma.
///
/// # Exemplos
///
/// ```
/// let resultado = meu_projeto::soma(2, 2);
/// assert_eq!(resultado, 4);
/// ```
pub fn soma(a: i32, b: i32) -> i32 {
a + b
}
Para gerar e abrir a documentação:
4. Testes Doc (Doc-tests) 🧪✨
Um dos recursos mais fantásticos do Rust: os exemplos de código na sua documentação são testados automaticamente pelo cargo test. Isso garante que sua documentação nunca fique desatualizada!
5. Visualização: Pirâmide de Testes no Rust 📐
graph TD
A["Testes Unitários (Muitos, rápidos, internos)"] --> B["Testes de Integração (Médios, externos)"]
B --> C["Doc-tests (Exemplos reais na documentação)"]
style A fill:#dfd
style C fill:#f9f
6. Mini-Projeto: Biblioteca de Utilidades Validada 📚
Crie um novo projeto de biblioteca (cargo new --lib minha_lib):
1. Implemente funções matemáticas simples.
2. Adicione documentação profissional com a seção # Exemplos.
3. Escreva testes unitários para cada função.
4. Crie um arquivo em tests/ para validar a integração das funções.
5. Gere a documentação e verifique se os exemplos estão renderizados corretamente.
7. Exercício de Fixação 🧠
- Qual a diferença de localização entre testes unitários e testes de integração?
- Para que serve o atributo
#[cfg(test)]? - Como o
rustdocajuda a manter o código e a documentação em sincronia?
Próxima Aula: Vamos encarar o desafio da Concorrência Segura! 🧵
Aula 13 - Concorrência Segura 🧵
Objetivo
Objetivo: Entender como o Rust garante a segurança em ambientes multi-thread, eliminando as temidas "corridas de dados" (data races) em tempo de compilação.
1. Concorrência Sem Medo 🛡️
O Rust utiliza seu sistema de Ownership e Tipagem para garantir que a memória seja acessada de forma segura por múltiplas threads.
Criando Threads
use std::thread;
use std::time::Duration;
fn main() {
thread::spawn(|| {
for i in 1..10 {
println!("Oi da thread spawned: {}", i);
thread::sleep(Duration::from_millis(1));
}
});
println!("Oi da thread principal!");
}
2. Passagem de Mensagens: Channels 📡
O Rust segue o lema: "Não comunique compartilhando memória; compartilhe memória comunicando". Os Channels (Canais) são a ferramenta para isso.
use std::sync::mpsc; // multiple producer, single consumer
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let val = String::from("oi");
tx.send(val).unwrap();
});
let recebido = rx.recv().unwrap();
println!("Recebido: {}", recebido);
}
3. Estado Compartilhado: Mutex e Arc 🔒
Quando você precisa compartilhar memória, o Rust exige o uso de ferramentas de sincronização.
- Mutex
: Garante que apenas uma thread acesse os dados por vez. - Arc
: Um ponteiro com contagem de referências atômicas, permitindo múltiplos donos em threads diferentes.
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
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());
}
4. Send e Sync: O Segredo das Traits 🧬
- Send: Permite que a posse do tipo seja transferida entre threads.
- Sync: Permite que o tipo seja acessado por múltiplas threads através de referências.
A maioria dos tipos básicos do Rust são Send e Sync. O compilador impede que você passe tipos inseguros para outras threads!
5. Visualização: Modelo de Comunicação 🔄
graph LR
T1[Thread 1] -- manda mensagem --> Canal((Canal / mpsc))
T2[Thread 2] -- manda mensagem --> Canal
Canal -- entrega --> Main[Thread Principal]
style Canal fill:#f9f,stroke:#333
6. Mini-Projeto: Processador de Imagens Multi-thread 🖼️
Crie uma simulação de processamento:
1. Um vetor de "IDs de imagens" (pode ser apenas números).
2. Use Arc e Mutex para manter uma lista de "Imagens Processadas".
3. Crie 4 threads que "processam" as imagens (use thread::sleep para simular trabalho).
4. Use um Channel para que cada thread avise a thread principal quando terminar uma imagem.
5. A thread principal deve exibir o progresso em tempo real.
7. Exercício de Fixação 🧠
- Por que o método
mpsc::channelse chama "mpsc" (Multiple Producer, Single Consumer)? - O que o método
lock()de um Mutex faz e o que acontece se outra thread já tiver o lock? - Explique a diferença entre
ArceRc(da aula de ponteiros inteligentes, se vista, ou pesquise a diferença atômica).
Próxima Aula: Vamos aplicar tudo em um Projeto CLI Profissional! 💻
Aula 14 - Projeto CLI Profissional 💻
Objetivo
Objetivo: Aplicar os conhecimentos adquiridos para construir uma ferramenta de linha de comando (CLI) funcional, tratando argumentos, lendo arquivos e utilizando o ecossistema de crates do Rust.
1. Tratando Argumentos da Linha de Comando ⌨️
O Rust fornece uma maneira básica de ler argumentos via std::env::args.
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
// O primeiro argumento é sempre o caminho do binário
let query = &args[1];
let file_path = &args[2];
println!("Buscando por: {}", query);
println!("No arquivo: {}", file_path);
}
2. Manipulando Arquivos 📄
Usamos o módulo std::fs para ler o conteúdo de arquivos de forma segura.
use std::fs;
fn main() {
let conteudo = fs::read_to_string("exemplo.txt")
.expect("Não foi possível ler o arquivo");
println!("Conteúdo:\n{conteudo}");
}
3. Melhorando a CLI com Crates Externas 📦
Para CLIs profissionais, a comunidade Rust utiliza a crate clap (Command Line Argument Parser). Ela gera ajuda automática (--help), valida tipos e muito mais.
Adicionando ao Cargo.toml
Usando o Clap
use clap::Parser;
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// Nome da pessoa para saudar
#[arg(short, long)]
nome: String,
/// Número de vezes para saudar
#[arg(short, long, default_value_t = 1)]
count: u8,
}
fn main() {
let args = Args::parse();
for _ in 0..args.count {
println!("Olá {}!", args.nome);
}
}
4. Visualização: Arquitetura da Ferramenta 🏗️
graph TD
A["Usuário (Terminal)"] --> B["Parser (Clap)"]
B --> C{Comando?}
C -->|Busca| D["Módulo de Arquivos"]
C -->|Config| E["Módulo de Setup"]
D --> F["Saída Formatada"]
5. Mini-Projeto: Clonando o 'grep' (minigrep) 🔍
Seu desafio é criar uma ferramenta de busca em arquivos:
1. Receba uma "string de busca" e um "caminho de arquivo".
2. Leia o arquivo e retorne apenas as linhas que contêm a string.
3. Adicione uma opção -i (case insensitive) usando o clap.
4. Trate erros de "Arquivo não encontrado" de forma amigável usando Result.
5. Organize o código em main.rs (interface) e lib.rs (lógica de busca).
6. Exercício de Fixação 🧠
- Por que o primeiro argumento de
std::env::args()é o caminho do próprio programa? - Qual a vantagem de mover a lógica principal para
lib.rsem um projeto CLI? - Como o
clapajuda na experiência do usuário final da sua ferramenta?
Próxima Aula: Vamos sair do terminal e ir para a internet com Rust para Web! 🌐
Aula 15 - Rust para Web (Introdução) 🌐
Objetivo
Objetivo: Entrar no mundo do desenvolvimento web com Rust, conhecendo o framework Actix Web e aprendendo a criar uma API REST básica, rápida e segura.
1. Por que usar Rust na Web? 🚀
Rust tem se tornado uma escolha popular para o backend devido a: - Performance Extrema: Ideal para serviços de alta carga. - Segurança: Previne crashes comuns em servidores C++/C. - Ecossistema: Frameworks como Actix Web e Axum são consistentemente os mais rápidos em benchmarks mundiais.
2. Olá, Actix Web! 🦀
O Actix Web é um framework poderoso, pragmático e extremamente rápido.
Configurando o Cargo.toml
[dependencies]
actix-web = "4"
serde = { version = "1.0", features = ["derive"] } # Para serialização JSON
Criando o Servidor Básico
use actix_web::{get, App, HttpResponse, HttpServer, Responder};
#[get("/")]
async fn hello() -> impl Responder {
HttpResponse::Ok().body("Olá, Actix Web! 🦀")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.service(hello)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
3. Rotas e JSON 🛰️
Servidores modernos geralmente se comunicam via JSON. O Rust usa a crate Serde para transformar Structs em JSON e vice-versa.
use actix_web::{post, web, HttpResponse, Responder};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct Info {
nome: String,
}
#[post("/echo")]
async fn echo(item: web::Json<Info>) -> impl Responder {
HttpResponse::Ok().json(item.0) // Retorna o JSON recebido
}
4. Visualização: Fluxo de uma Requisição 🔄
graph LR
A["Cliente (Browser/Postman)"] -- GET /produtos --> B["Actix Web Server"]
B --> C{Roteamento}
C -->|Match| D["Handler Function (Async)"]
D --> E["Lógica / Banco de Dados"]
E --> F["HttpResponse (JSON)"]
F -- 200 OK --> A
style B fill:#f96,stroke:#333
5. Mini-Projeto: API de Lista de Compras 🛒
Desenvolva um servidor web que:
1. Tenha uma rota GET /itens que retorne uma lista de itens em JSON.
2. Tenha uma rota POST /itens que receba um novo item e o "adicione" (por enquanto, apenas imprima no console e retorne sucesso).
3. Utilize Structs com Serialize e Deserialize.
4. Teste as rotas usando o Postman ou o comando curl.
6. Exercício de Fixação 🧠
- O que significa o atributo
#[actix_web::main]e a palavra-chaveasync? - Para que serve a crate Serde no contexto de uma API web?
- Qual a principal diferença entre um método
GETe um métodoPOST?
Próxima Aula: Vamos encerrar o curso com o Projeto Final e as Tendências do Mercado! 🚀
Aula 16 - Projeto Final e Tendências 🚀
Objetivo
Objetivo: Consolidar o aprendizado com um projeto integrador, aprender a publicar seu trabalho no ecossistema Rust e vislumbrar o futuro da tecnologia com WebAssembly e o mercado profissional.
1. Projeto Final: API de Gerenciamento de Tarefas (V2) 📝
Chegou a hora de unir tudo o que aprendemos. Seu projeto final deve ser uma API REST que aplica:
- Structs e Enums: Para representar tarefas e status.
- Ownership e Borrowing: Em toda a manipulação de dados.
- Tratamento de Erros: Com Result e mensagens claras.
- Concorrência: (Bônus) Use threads para processar tarefas em background.
- Persistência: (Bônus) Salve os dados em um arquivo JSON.
2. Publicando no Mundo Rust: Crates.io e GitHub 🌍
Para ser um profissional, seu código precisa estar visível.
- GitHub: Onde seu código mora. Use o README.md para documentar como rodar o projeto.
- Crates.io: O registro oficial de pacotes Rust. Se você criou uma biblioteca útil, publique-a lá!
3. O Futuro: Rust + WebAssembly (Wasm) 🕸️
WebAssembly permite rodar código de alta performance no navegador. O Rust é a linguagem número 1 para Wasm devido ao seu tamanho de binário pequeno e ausência de Garbage Collector.
graph LR
A["Código Rust"] -- rustc + wasm-pack --> B["Arquivo .wasm"]
B --> C["Navegador (JS interop)"]
C --> D["Performance de Nativo na Web"]
style B fill:#f96,stroke:#333
4. Mercado e Aplicações Profissionais 💼
Onde o Rust é usado hoje? - Sistemas Operacionais: Componentes do Windows, Linux e Android. - Blockchain: Solana e Polkadot. - Cloud Infrastructure: AWS, Google e Microsoft usam para seus serviços de core. - Ferramentas de Dev: O VS Code e o Terminal do Windows usam Rust para velocidade.
5. Visualização: Sua Jornada de Aprendizado 🎓
mindmap
root((Rust🦀))
Fundamentos
Ownership
Borrow Checker
Tipos Primitivos
Estruturas
Structs
Enums
Generics
Aplicações
CLI Tools
Web APIs
WebAssembly
Qualidade
Testes
Documentação
Segurança
6. Considerações Finais e Próximos Passos 👋
Parabéns por concluir este curso! Rust é uma jornada contínua. Para continuar evoluindo: 1. Leia o "The Rust Book". 2. Pratique no Rustlings. 3. Participe da comunidade brasileira no Discord/Telegram.
Obrigado e boa sorte em sua carreira como desenvolvedor Rust! 🚀🦀
Exercícios
Banco de Exercícios 🏋️
Esta seção contém todos os exercícios práticos do curso, divididos por aula. Cada arquivo contém 5 desafios (2 básicos, 2 intermediários e 1 desafio).
📝 Lista de Exercícios
| Aula | Tópico | Link |
|---|---|---|
| 01 | Introdução e Setup | Acessar Exercício |
| 02 | Fundamentos | Acessar Exercício |
| 03 | Controle de Fluxo | Acessar Exercício |
| 04 | Funções e Módulos | Acessar Exercício |
| 05 | Ownership Parte 1 | Acessar Exercício |
| 06 | Borrowing e Referências | Acessar Exercício |
| 07 | Strings e Coleções | Acessar Exercício |
| 08 | Structs e Enums | Acessar Exercício |
| 09 | Tratamento de Erros | Acessar Exercício |
| 10 | Generics e Traits | Acessar Exercício |
| 11 | Programação Funcional | Acessar Exercício |
| 12 | Testes e Documentação | Acessar Exercício |
| 13 | Concorrência Segura | Acessar Exercício |
| 14 | Projeto CLI Profissional | Acessar Exercício |
| 15 | Rust para Web | Acessar Exercício |
| 16 | Projeto Final | Acessar Exercício |
Como Praticar
Tente resolver os exercícios básicos logo após a aula. Os desafios intermediários e o "Boss Level" (Desafio) podem exigir uma consulta extra à documentação oficial!
Exercícios: Aula 01 - Introdução e Setup 🦀
🟢 Básico
- Instalação: Execute
rustc --versionno seu terminal e cole a saída abaixo. Por que é importante ter orustupgerenciando essa versão? - Primeiro Cargo: Crie um novo projeto chamado
exercicio_01usando o Cargo. Qual comando você usou e quais arquivos foram criados automaticamente?
🟡 Intermediário
- Compilação vs Execução: Explique a diferença entre rodar
cargo buildecargo run. Em qual pasta o binário final é gerado por padrão? - Ecossistema: Pesquise e cite 3 grandes empresas que utilizam Rust hoje e em quais projetos elas o aplicam.
🔴 Desafio
- Análise de Performance: Escreva um pequeno programa que imprima "Iniciando contagem..." e depois conte de 1 a 1.000.000 em um loop. Use o comando
time(Linux/Mac) ouMeasure-Command(PowerShell) para medir quanto tempo o Rust leva para executar esse binário gerado comcargo build --release.
Exercícios: Aula 02 - Fundamentos 🧩
🟢 Básico
- Imutabilidade: Tente compilar o código abaixo. Corrija o erro sem remover a linha 3.
- Tipos Primitivos: Declare um array com os nomes de 5 frutas e uma tupla contendo o nome, idade e se uma pessoa é estudante (bool).
🟡 Intermediário
- Shadowing: Crie um programa que use shadowing para mudar o tipo de uma variável de
String(contendo o número "42") para umi32e realize uma soma. - Aritmética e Tipos: O que acontece se você tentar somar um
i32com umf64? Escreva um código que realize essa operação usando a conversãoas.
🔴 Desafio
- Análise de Estouro: O tipo
u8pode armazenar valores de 0 a 255. O que acontece se você usar uma variável mutávelu8com valor 255 e tentar somar 1? Teste isso usandocargo runem modo debug e em modo release (--release). Explique a diferença de comportamento.
Exercícios: Aula 03 - Controle de Fluxo 🔄
🟢 Básico
- Par ou Ímpar: Peça um número ao usuário e use
if/elsepara imprimir se ele é par ou ímpar. - Contagem Regressiva: Use um loop
whilepara fazer uma contagem regressiva de 10 até 0.
🟡 Intermediário
- Classificador de Idade: Use
matchcom ranges (ex:13..=19) para classificar uma idade em: Criança, Adolescente, Adulto ou Idoso. - Soma com Loop: Use o loop
loope a palavra-chavebreakcom retorno para somar números de 1 a 50 e armazenar o resultado final em uma variável.
🔴 Desafio
- FizzBuzz Rustacean: Escreva o clássico FizzBuzz de 1 a 100, mas use
matchcom uma tupla(n % 3, n % 5)em vez de váriosif/else.
Exercícios: Aula 04 - Funções e Organização 📦
🟢 Básico
- Soma Simples: Crie uma função
somar(a: i32, b: i32) -> i32e chame-a nomain. - Conversor de Horas: Crie uma função que receba um valor em horas e retorne o total em minutos.
🟡 Intermediário
- Expressões: Crie um bloco de código (expressão) dentro do
mainque calcule a área de um círculo e atribua o resultado a uma variável, sem usar uma função externa. - Módulo Matemático: Crie um arquivo
math_utils.rs, defina uma função pública para calcular o fatorial de um número e use-a no seumain.rs.
🔴 Desafio
- Calculadora de IMC Modular: Organize um projeto com três arquivos:
main.rs,io_utils.rs(para ler dados do usuário) ecalc_utils.rs(para fórmulas de IMC). O programa deve ler peso e altura, calcular o IMC e retornar a classificação.
Exercícios: Aula 05 - Ownership 🧠
🟢 Básico
- Regras de Ouro: Cite as três regras fundamentais do Ownership no Rust.
- Stack vs Heap: Explique por que o Rust limpa os dados da Heap quando o dono sai de escopo e como isso evita vazamentos de memória.
🟡 Intermediário
- Identificando Erros: Por que o código abaixo falha ao compilar? Corrija-o usando
.clone(). - Ownership em Funções: Escreva um código onde uma
Stringé passada para uma função e depois você tenta usá-la nomain. Mostre como "devolver" a posse da String para omainatravés do retorno da função.
🔴 Desafio
- Simulando Memória: Desenhe (em formato de comentário ou diagrama) o que acontece com as variáveis
s1es2na Stack e na Heap durante um processo deMovevs um processo deClone.
Exercícios: Aula 06 - Borrowing e Referências 🤝
🟢 Básico
- Imutabilidade por Padrão: Por que o código abaixo não compila? Como você o corrigiria usando referências?
- Símbolos: Explique a diferença entre usar
&Stringe&mut Stringcomo parâmetro de uma função.
🟡 Intermediário
- Regra de Ouro: Escreva um código que tente criar duas referências mutáveis para a mesma variável e mostre o erro do compilador. Em seguida, explique por que essa regra existe.
- Escopo de Referência: Crie um programa onde você declara uma referência imutável, usa-a, e logo abaixo declara uma referência mutável. Mostre que isso funciona desde que a referência imutável não seja mais usada após a criação da mutável.
🔴 Desafio
- Simulador de Empréstimo: Crie uma função que receba uma referência mutável a um
Vec<i32>e adicione a soma de todos os seus elementos como um novo elemento ao final do vetor.
Exercícios: Aula 07 - Strings e Coleções 🧵
🟢 Básico
- Soma de Vetor: Crie um
Vec<i32>, adicione 5 números a ele e calcule a soma total. - Diferença de Texto: Explique, com um exemplo de código, quando usar
Stringem vez de&str.
🟡 Intermediário
- Média de Notas: Use um
Vec<f64>para armazenar notas de um aluno. Calcule a média e use umifpara dizer se ele foi aprovado (média >= 7). - Dicionário Simples: Use um
HashMap<String, String>para criar um pequeno tradutor (Português -> Inglês) com pelo menos 5 palavras.
🔴 Desafio
- Contador de Palavras: Receba uma frase (String) do usuário e use um
HashMap<String, u32>para contar quantas vezes cada palavra aparece na frase.
Exercícios: Aula 08 - Structs e Enums 🏗️
🟢 Básico
- Dados Pessoais: Crie uma
struct Pessoacom camposnome,idadeeemail. Instancie duas pessoas nomain. - Cores Enums: Crie um
enum Corcom as variantesVermelho,Verde,AzulePersonalizada(u8, u8, u8).
🟡 Intermediário
- Área do Retângulo: Adicione um bloco
implpara astruct Retangulocom um métodonova(l: u32, a: u32) -> Retangulo(construtor) e um métodoarea(&self) -> u32. - Option Safe: Crie uma função que receba um
Vec<i32>e retorne umOption<i32>contendo o primeiro elemento, se existir.
🔴 Desafio
- Calculadora de Formas: Crie um
enum Formaque pode ser umCirculo(f64)ou umQuadrado(f64). Implemente um métodoareapara o enumFormaque usematchpara calcular a área dependendo da variante.
Exercícios: Aula 09 - Tratamento de Erros ⚠️
🟢 Básico
- Entendendo o Result: Explique a diferença entre usar
.unwrap()e tratar um erro commatch. Quando você usaria cada um? - Panic Forçado: Crie um programa simples que peça um número ao usuário e chame
panic!se o número for negativo.
🟡 Intermediário
- Leitura Segura: Escreva uma função que tente ler um arquivo e retorne o conteúdo em uma
String. UseResult<String, io::Error>como retorno. - Operador Interrogação: Refaça o exercício anterior usando o operador
?para propagar o erro, em vez de usarmatch.
🔴 Desafio
- Validador de Login: Crie um sistema de login simples que retorne um
Result<(), String>. Se a senha for "rust123", retorneOk(()). Caso contrário, retorne umErrcom uma mensagem explicativa. Nomain, trate esse erro e peça para o usuário tentar novamente até acertar.
Exercícios: Aula 10 - Generics e Traits 🧬
🟢 Básico
- Par Genérico: Crie uma
struct Par<T>que armazene dois valores do mesmo tipoT. Instancie um par dei32e um par deString. - Trait de Fala: Defina uma
trait Falacom um métodofalar(&self). Implemente-a para umastruct Cachorroe umastruct Gato.
🟡 Intermediário
- Comparador Genérico: Escreva uma função genérica chamada
imprimir_se_maior<T: PartialOrd + std::fmt::Display>(a: T, b: T)que compare dois valores e imprima o maior deles. - Implementação de Trait: Implemente a trait
std::fmt::Displaypara uma structPonto { x: i32, y: i32 }para que ela possa ser impressa diretamente comprintln!("{}", ponto).
🔴 Desafio
- Área em Traits: Crie uma trait
Formacom o métodoarea(&self) -> f64. Implemente essa trait paraCirculoeRetangulo. Em seguida, crie uma função que receba uma referência genérica&TondeT: Formae imprima a área formatada.
Exercícios: Aula 11 - Programação Funcional 🚀
🟢 Básico
- Closure Simples: Crie uma closure que receba um número e retorne o seu quadrado. Use-a em uma variável.
- Iterador Básico: Crie um vetor de 1 a 10. Use o método
.iter()e um loopforpara imprimir cada valor multiplicado por 2.
🟡 Intermediário
- Filtragem de Dados: Use
.iter(),.filter()e.collect()para criar um novo vetor contendo apenas os números pares de um vetor original. - Soma com Fold: Pesquise o método
.fold()(ou.sum()) dos iteradores e use-o para calcular a soma de todos os elementos de um vetor sem usar loopsforouwhile.
🔴 Desafio
- Pipeline de Strings: Dado um vetor de strings
vec!["maçã", "banana", "uva", "abacaxi"], crie um pipeline que:- Filtre apenas as frutas com mais de 4 letras.
- Transforme todas em letras maiúsculas (uppercase).
- Colete o resultado em um novo
Vec<String>.
Exercícios: Aula 12 - Testes e Documentação 🧪
🟢 Básico
- Macro de Asserção: Qual a diferença entre
assert!,assert_eq!eassert_ne!? Dê um exemplo de uso para cada um. - Comentários Doc: Crie uma função simples e adicione comentários de documentação usando
///. O que acontece quando você rodacargo doc --open?
🟡 Intermediário
- Teste Unitário: Crie uma função que valide se um e-mail é válido (verifique se contém "@"). Escreva pelo menos dois testes unitários dentro do mesmo arquivo: um para um caso de sucesso e outro para uma falha.
- Atributo Should Panic: Pesquise sobre o atributo
#[should_panic]e escreva um teste que passe apenas se a função testada causar umpanic!.
🔴 Desafio
- TDD (Test Driven Development): Sem escrever a implementação primeiro, crie os testes para uma função
parske_kelvin_to_celsius(k: f64) -> Result<f64, String>. O teste deve validar que:- O cálculo está correto.
- Se a temperatura for menor que 0 absoluto (-273.15 C), deve retornar um
Err. Depois, implemente a função até que todos os testes passem.
Exercícios: Aula 13 - Concorrência Segura 🧵
🟢 Básico
- Spawn de Thread: Crie um programa que faça o spawn de uma thread que imprima números de 1 a 5, enquanto a thread principal imprime de 6 a 10. Use o método
joinpara garantir que ambas terminem antes do programa fechar. - MPSC: Qual o significado da sigla
mpsce por que ela é importante para a segurança de memória no Rust?
🟡 Intermediário
- Comunicação via Canais: Crie um programa onde uma thread secundária calcula o fatorial de um número e envia o resultado para a thread principal através de um canal (
channel). - Estado Compartilhado: Use
ArceMutexpara incrementar um contador compartilhado entre 10 threads diferentes. Imprima o valor final nomain.
🔴 Desafio
- Simulador de Corridas: Crie um programa onde 3 threads "correm" (cada uma imprime seu progresso em intervalos de tempo aleatórios usando
thread::sleep). Use um canal para avisar a thread principal quando cada thread cruzar a linha de chegada. A thread principal deve anunciar o 1º, 2º e 3º lugares.
Exercícios: Aula 14 - Projeto CLI Profissional 💻
🟢 Básico
- Args Simples: Escreva um programa que imprima o número total de argumentos recebidos e o valor do segundo argumento.
- Lendo Arquivo: Use
std::fs::read_to_stringpara ler um arquivo chamadoteste.txte imprimir o número de caracteres que ele possui.
🟡 Intermediário
- Busca de Texto: Crie uma ferramenta CLI que receba uma palavra e um nome de arquivo. Ela deve imprimir "Encontrado!" ou "Não encontrado!" se a palavra estiver no arquivo.
- Uso do Clap: Configure um projeto com a crate
clapque aceite dois argumentos nomeados:--origeme--destino. Printe os valores recebidos.
🔴 Desafio
- Mini Gerenciador de Notas: Crie uma CLI que aceite dois comandos:
add "minha nota": Salva a nota em um arquivonotas.txt.list: Lê o arquivonotas.txte imprime todas as notas numeradas. Use oclappara gerenciar os subcomandos.
Exercícios: Aula 15 - Rust para Web (Introdução) 🌐
🟢 Básico
- Ecossistema Web: Cite 2 frameworks web para Rust além do Actix Web e comente uma característica de cada um.
- Status HTTP: O que o método
HttpResponse::Ok()faz e qual é o código numérico associado a ele?
🟡 Intermediário
- Nova Rota: Crie uma rota
GET /dataque retorne a data e hora atual (pode ser uma string estática para simplificar). - Parâmetros de Rota: Use o
web::Pathdo Actix para criar uma rota que receba um nome na URL (ex:/saudacao/{nome}) e retorne uma mensagem personalizada como "Olá, {nome}!".
🔴 Desafio
- CRUD Simples (Memória): Crie uma API que gerencie uma lista de strings em memória.
GET /lista: Retorna todas as strings em JSON.POST /adicionar: Recebe um JSON{"item": "texto"}e adiciona à lista. (Dica: Você precisará usar umweb::Datacom umMutexpara compartilhar a lista entre as threads do servidor).
Exercícios: Aula 16 - Projeto Final e Tendências 🚀
🟢 Básico
- Portfólio: Crie um repositório no GitHub para o seu projeto final. Adicione um
README.mdbem formatado contando o que você aprendeu no curso. - WebAssembly: Pesquise e cite uma aplicação famosa que utiliza WebAssembly hoje e por que o Rust foi escolhido para ela.
🟡 Intermediário
- Refatoração Rust: Pegue um código antigo seu (em qualquer linguagem) e tente reescrever uma pequena parte dele em Rust, focando em como o Ownership mudaria a estrutura original do programa.
- Crates de Mercado: Escolha uma crate famosa no Crates.io (ex:
tokio,serde,rand,reqwest) e escreva um pequeno exemplo funcional de como utilizá-la.
🔴 Desafio
- Expandindo o Wasm: Siga o guia do RustWasm Book e compile um programa "Olá Mundo" em Rust para rodar no navegador. Documente os passos e o que mudou na forma de compilar o binário.
Projetos
Portfólio de Projetos 🚀
A melhor forma de aprender Rust é construindo. Aqui você encontra 16 mini-projetos que escalam em complexidade junto com o seu conhecimento.
🛠️ Lista de Projetos
| Aula | Nome do Projeto | Foco Técnico | Link |
|---|---|---|---|
| 01 | Dashboard | Setup e Git | Ver Projeto |
| 02 | Conversor Espacial | Tipos e Constantes | Ver Projeto |
| 03 | Simulador Elevador | Match e Loops | Ver Projeto |
| 04 | Conversor Modular | Módulos e Funções | Ver Projeto |
| 05 | String Safe | Ownership e Move | Ver Projeto |
| 06 | Analisador Texto | Ref e Borrowing | Ver Projeto |
| 07 | Agenda HashMap | Coleções | Ver Projeto |
| 08 | Biblio Model | Structs e Enums | Ver Projeto |
| 09 | Validador Seguro | Erros e Result | Ver Projeto |
| 10 | Calculadora Geo | Generics e Traits | Ver Projeto |
| 11 | Vendas Funcional | Closures/Iterators | Ver Projeto |
| 12 | Senhas Testadas | Testes e Docs | Ver Projeto |
| 13 | Log Concorrente | Threads e Canais | Ver Projeto |
| 14 | Todo CLI Pro | Crate Clap e I/O | Ver Projeto |
| 15 | API Saudação | Actix Web e JSON | Ver Projeto |
| 16 | Gerenciador Final | Integração Total | Ver Projeto |
Dica para o Aluno
Ao final do curso, você terá 16 repositórios (ou um monorepo) com soluções robustas para apresentar em seu portfólio profissional.
Mini-Projeto: Dashboard de Ferramentas 🛠️
Neste primeiro mini-projeto, seu objetivo é validar o seu ambiente de desenvolvimento e criar o seu primeiro repositório oficial de estudos de Rust.
📋 Requisitos
- Verificação do Sistema: O programa deve imprimir a versão instalada do compilador Rust (
rustc) e do Cargo. - Primeiro Repositório: Inicialize um repositório Git dentro da pasta do projeto.
- Mensagem Customizada: O código fonte (
main.rs) deve imprimir: "Ambiente Rust configurado por [Seu Nome]! 🦀".
🚀 Guia de Execução
- Abra seu terminal.
- Crie o projeto:
- Edite o arquivo
src/main.rs: - Execute o programa:
✅ Critérios de Aceite
- [ ] O programa compila sem erros.
- [ ] A saída no terminal mostra o seu nome e o emoji do caranguejo.
- [ ] O projeto possui um arquivo
.gitignore(criado automaticamente pelo Cargo).
Mini-Projeto: Conversor de Unidades Espaciais 🚀
Vamos aplicar os conceitos de variáveis, constantes e tipos primitivos para criar um conversor de medidas astronômicas.
📋 Requisitos
- Constantes: Defina uma constante para a velocidade da luz (aprox. 299.792 km/s).
- Shadowing: Use shadowing para transformar um valor de entrada (distância em km) em uma mensagem de texto explicativa.
- Tipos: Use tipos de ponto flutuante (
f64) para precisão e transforme-os em inteiros quando necessário.
🚀 Guia de Execução
- Crie o projeto:
cargo new conversor_espacial. - No
main.rs, defina a constante:const VELOCIDADE_LUZ: f64 = 299792.0; fn main() { let distancia_marte_km = 225_000_000.0; // Calcule o tempo que a luz leva de Marte à Terra (em segundos) let tempo_segundos = distancia_marte_km / VELOCIDADE_LUZ; // Use shadowing para formatar o resultado let tempo_segundos = format!("{:.2} segundos", tempo_segundos); println!("A luz de Marte leva {} para chegar à Terra.", tempo_segundos); }
✅ Critérios de Aceite
- [ ] Uso correto da palavra-chave
const. - [ ] Demonstração prática de shadowing de variável.
- [ ] O programa realiza o cálculo matemático correto.
Mini-Projeto: Simulador de Elevador 🏢
Neste projeto, vamos usar o poder do match e dos loops para controlar a lógica de um elevador em um prédio de 10 andares.
📋 Requisitos
- Estado do Elevador: Mantenha o andar atual em uma variável mutável.
- Match Exaustivo: Use
matchpara lidar com os comandos: "Sobe", "Desce" e "Sair". - Limite de Segurança: O elevador não deve subir acima do 10º andar nem descer abaixo do térreo (0).
- Loop Principal: O programa deve rodar continuamente até que o usuário escolha "Sair".
🚀 Guia de Execução
- Estrutura básica:
fn main() { let mut andar_atual = 0; loop { println!("--- Elevador (Andar: {}) ---", andar_atual); println!("Comandos: [s]obe, [d]esce, [q]uit"); // Simulação de entrada (em um projeto real usaríamos std::io) let comando = "s"; // Mude aqui para testar match comando { "s" => { if andar_atual < 10 { andar_atual += 1; println!("Subindo..."); } else { println!("Já estamos no topo!"); } }, "d" => { if andar_atual > 0 { andar_atual -= 1; println!("Descendo..."); } else { println!("Já estamos no térreo!"); } }, "q" => { println!("Desligando elevador..."); break; }, _ => println!("Comando inválido!"), } // Remova o break se estiver usando entrada real de teclado break; } }
✅ Critérios de Aceite
- [ ] O elevador respeita os limites (0 a 10).
- [ ] O
matchtrata todos os comandos e o caso padrão. - [ ] O loop é encerrado corretamente com o comando de saída.
Mini-Projeto: Sistema de Conversão Modular 🌡️
Neste projeto, vamos organizar um conversor de temperaturas profissional, dividindo a lógica em diferentes módulos.
📋 Requisitos
- Modularização: Crie um arquivo
conversor.rspara as fórmulas e use-o nomain.rs. - Funções: Implemente funções separadas para Celsius para Fahrenheit e vice-versa.
- Assinaturas: As funções devem receber
f64e retornarf64.
🚀 Guia de Execução
- Crie o projeto:
cargo new conversor_modular. - Crie o arquivo
src/conversor.rs: - No seu
src/main.rs:
✅ Critérios de Aceite
- [ ] O projeto está dividido em pelo menos dois arquivos
.rs. - [ ] As funções utilizam parâmetros e retorno de forma correta.
- [ ] O uso de
pubgarante a visibilidade das funções nomain.rs.
Mini-Projeto: Manipulador de Strings Seguro 🧵
Neste projeto, você vai provar que entendeu o Ownership criando um programa que transfere e clona dados na memória.
📋 Requisitos
- Transferência de Posse: Crie uma função que receba a posse de uma
String, modifique-a e a retorne. - Clone Explícito: Demonstre o uso do
.clone()para manter a variável original válida após passar a cópia para outra função. - Análise de Erro: Comente no código por que um simples
let s2 = s1impediria o uso des1posteriormente.
🚀 Guia de Execução
- Implementação sugerida:
fn processar_texto(mut texto: String) -> String { texto.push_str(" [Processado]"); texto } fn main() { let original = String::from("Dados confidenciais"); // Clonamos para manter a 'original' válida let copia = original.clone(); let resultado = processar_texto(copia); println!("Original: {}", original); println!("Resultado: {}", resultado); }
✅ Critérios de Aceite
- [ ] O programa utiliza
String::frompara alocação na Heap. - [ ] O uso de
.clone()é justificado e funcional. - [ ] A posse é transferida e retornada corretamente via funções.
Mini-Projeto: Analisador de Texto Eficiente 🔍
Vamos aprender a economizar memória usando referências para analisar dados sem precisar cloná-los.
📋 Requisitos
- Imutabilidade: Uma função deve receber uma referência imutável (
&String) e contar quantas vogais existem no texto. - Mutabilidade Controlada: Uma função deve receber uma referência mutável (
&mut String) e transformar todo o texto em letras maiúsculas. - Segurança: Demonstre que você não pode chamar as duas funções ao mesmo tempo se as referências estiverem ativas.
🚀 Guia de Execução
- Implementação sugerida:
fn contar_vogais(texto: &String) -> usize { texto.chars().filter(|c| "aeiouAEIOU".contains(*c)).count() } fn tornar_maiusculo(texto: &mut String) { *texto = texto.to_uppercase(); } fn main() { let mut documento = String::from("Rust é fantástico"); let n_vogais = contar_vogais(&documento); println!("Vogais encontradas: {}", n_vogais); tornar_maiusculo(&mut documento); println!("Documento final: {}", documento); }
✅ Critérios de Aceite
- [ ] Uso correto dos símbolos
&e&mut. - [ ] O programa não realiza clones desnecessários de dados.
- [ ] As funções demonstram clareza na intenção de uso dos dados (leitura vs escrita).
Mini-Projeto: Agenda de Contatos 📞
Neste projeto, vamos usar o HashMap para criar uma agenda de contatos extremamente rápida e eficiente.
📋 Requisitos
- Armazenamento: Use um
HashMap<String, String>onde a chave é o nome e o valor é o telefone. - Operações: O programa deve permitir adicionar, buscar e remover contatos.
- Listagem: Use um loop
forpara imprimir todos os contatos da agenda.
🚀 Guia de Execução
- Estrutura sugerida:
use std::collections::HashMap; fn main() { let mut agenda = HashMap::new(); // 1. Adicionar agenda.insert(String::from("Alice"), String::from("9999-8888")); agenda.insert(String::from("Bob"), String::from("8888-7777")); // 2. Buscar let nome_busca = "Alice"; match agenda.get(nome_busca) { Some(tel) => println!("Telefone de {}: {}", nome_busca, tel), None => println!("Contato não encontrado!"), } // 3. Listar tudo println!("\nMinha Agenda:"); for (nome, tel) in &agenda { println!("- {}: {}", nome, tel); } }
✅ Critérios de Aceite
- [ ] O
HashMapé utilizado corretamente para indexar os contatos. - [ ] O programa lida com a ausência de chaves de forma segura (usando
matchouif let). - [ ] O código demonstra o uso de referências ao iterar pela coleção.
Mini-Projeto: Gerenciador de Biblioteca 📚
Vamos usar Structs e Enums para modelar um sistema real de biblioteca, controlando o status de cada livro.
📋 Requisitos
- Enum de Status: Crie um
enum Statuscom as variantesDisponiveleEmprestado(String)(onde a string guarda o nome de quem pegou). - Struct de Livro: Crie uma
struct Livrocom campos paratitulo,autore ostatus. - Métodos (impl): Implemente métodos para criar um novo livro e para realizar um empréstimo (mudando o status).
🚀 Guia de Execução
- Implementação sugerida:
#[derive(Debug)] enum Status { Disponivel, Emprestado(String), } struct Livro { titulo: String, autor: String, status: Status, } impl Livro { fn novo(titulo: &str, autor: &str) -> Livro { Livro { titulo: String::from(titulo), autor: String::from(autor), status: Status::Disponivel, } } fn emprestar(&mut self, nome: String) { self.status = Status::Emprestado(nome); } } fn main() { let mut livro = Livro::novo("O Programador Pragmático", "Andrew Hunt"); println!("Livro: {} | Status: {:?}", livro.titulo, livro.status); livro.emprestar(String::from("Ricardo")); println!("Após empréstimo: Status: {:?}", livro.status); }
✅ Critérios de Aceite
- [ ] Uso correto de Enums com dados internos.
- [ ] Implementação de métodos através do bloco
impl. - [ ] O programa demonstra a mudança de estado interna de uma estrutura.
Mini-Projeto: Validador de Arquivos Seguro 🛡️
Neste projeto, você vai construir uma pequena ferramenta que lê arquivos de configuração, lidando com erros de forma profissional usando Result.
📋 Requisitos
- Tratamento de I/O: Tente abrir um arquivo chamado
config.txt. - Operador ?: Use o operador de interrogação para propagar erros de leitura.
- Resultado Amigável: No
main, usematchpara imprimir uma mensagem personalizada se o arquivo não for encontrado.
🚀 Guia de Execução
- Implementação sugerida:
use std::fs::File; use std::io::{self, Read}; fn ler_configuracao() -> Result<String, io::Error> { let mut arquivo = File::open("config.txt")?; // Propaga se falhar let mut conteudo = String::new(); arquivo.read_to_string(&mut conteudo)?; Ok(conteudo) } fn main() { match ler_configuracao() { Ok(c) => println!("Configuração carregada: {}", c), Err(e) => { match e.kind() { io::ErrorKind::NotFound => println!("Erro: O arquivo 'config.txt' não existe!"), _ => println!("Ocorreu um erro inesperado: {}", e), } } } }
✅ Critérios de Aceite
- [ ] Uso correto do tipo
Result<T, E>. - [ ] Demonstração prática do operador
?. - [ ] Tratamento de erro específico no
mainviamatch.
Mini-Projeto: Calculadora Geométrica Genérica 📐
Neste projeto, vamos usar Generics e Traits para criar um sistema que calcula áreas de diferentes formas geométricas de forma flexível.
📋 Requisitos
- Trait Area: Defina uma trait
Areacom um métodocalcular_area(&self) -> f64. - Formas: Implemente a trait para uma
struct Circuloe umastruct Retangulo. - Função Genérica: Escreva uma função que receba qualquer tipo que implemente
Areae imprima o resultado formatado.
🚀 Guia de Execução
- Implementação sugerida:
trait Area { fn calcular_area(&self) -> f64; } struct Circulo { raio: f64 } struct Retangulo { largura: f64, altura: f64 } impl Area for Circulo { fn calcular_area(&self) -> f64 { std::f64::consts::PI * self.raio * self.raio } } impl Area for Retangulo { fn calcular_area(&self) -> f64 { self.largura * self.altura } } // Função genérica com Trait Bound fn exibir_area<T: Area>(forma: T) { println!("A área da forma é: {:.2}", forma.calcular_area()); } fn main() { let c = Circulo { raio: 5.0 }; let r = Retangulo { largura: 10.0, altura: 2.0 }; exibir_area(c); exibir_area(r); }
✅ Critérios de Aceite
- [ ] Definição e implementação correta de uma Trait.
- [ ] Uso de Generics com Trait Bounds (
<T: Area>). - [ ] O programa realiza cálculos precisos para diferentes tipos.
Mini-Projeto: Processador de Vendas Funcional 💰
Neste projeto, vamos usar o poder dos Iteradores e Closures para processar uma lista de vendas de forma limpa e eficiente.
📋 Requisitos
- Dados: Tenha um vetor de tuplas
(cliente, valor). - Transformação: Aplique um "imposto" de 10% sobre todos os valores usando
.map(). - Filtragem: Mantenha apenas as vendas que, após o imposto, resultem em um valor maior que 50.
- Agregação: Calcule o valor total das vendas filtradas usando
.sum()ou.fold().
🚀 Guia de Execução
- Implementação sugerida:
fn main() { let vendas = vec![ ("Alice", 100.0), ("Bob", 30.0), ("Charlie", 50.0), ("David", 200.0), ]; let imposto = 1.10; let total_vendas_grandes: f64 = vendas.iter() .map(|(_, valor)| valor * imposto) // Aplica imposto .filter(|&valor_final| valor_final > 50.0) // Filtra grandes .sum(); // Soma tudo println!("O total das vendas processadas é: R${:.2}", total_vendas_grandes); }
✅ Critérios de Aceite
- [ ] O código não utiliza loops
forouwhilemanuais. - [ ] O pipeline de iteradores é claro e funcional.
- [ ] O uso de closures captura as variáveis de ambiente necessárias.
Mini-Projeto: API de Saudação Moderna 🌐
Vamos construir seu primeiro servidor web usando o Rust, focando em rotas dinâmicas e retorno de dados em JSON.
📋 Requisitos
- Framework: Use o
actix-web. - Rotas:
GET /: Retorna um "Bem-vindo!" em texto simples.GET /saudacao/{nome}: Retorna um JSON{"mensagem": "Olá, {nome}!"}.
- Serialização: Use a crate
serdepara gerar o JSON automaticamente.
🚀 Guia de Execução
- Adicione as dependências:
- Implementação sugerida:
use actix_web::{get, web, App, HttpServer, Responder, HttpResponse}; use serde::Serialize; #[derive(Serialize)] struct Resposta { mensagem: String, } #[get("/")] async fn index() -> impl Responder { HttpResponse::Ok().body("Bem-vindo à API Rust!") } #[get("/saudacao/{nome}")] async fn saudar(nome: web::Path<String>) -> impl Responder { let resposta = Resposta { mensagem: format!("Olá, {}!", nome), }; HttpResponse::Ok().json(resposta) } #[actix_web::main] async fn main() -> std::io::Result<()> { println!("Servidor rodando em http://localhost:8080"); HttpServer::new(|| { App::new() .service(index) .service(saudar) }) .bind("127.0.0.1:8080")? .run() .await }
✅ Critérios de Aceite
- [ ] O servidor inicia corretamente e responde na porta 8080.
- [ ] A rota de saudação retorna um JSON bem formatado.
- [ ] O código utiliza
async/awaite o atributo#[actix_web::main].
Mini-Projeto: Processador de Logs Concorrente ⚡
Neste projeto, vamos simular o processamento de grandes arquivos de log usando Threads e Canais para ganhar performance.
📋 Requisitos
- Paralelismo: Crie 4 threads para "processar" diferentes partes de um log (simulado por um vetor).
- Mensageria: Use um canal (
mpsc) para enviar os resultados (quantidade de erros encontrados) de cada thread para a thread principal. - Sincronização: A thread principal deve esperar todos os resultados e imprimir o total final de erros.
🚀 Guia de Execução
- Implementação sugerida:
use std::sync::mpsc; use std::thread; use std::time::Duration; fn main() { let (tx, rx) = mpsc::channel(); let logs = vec!["INFO", "ERROR", "INFO", "ERROR", "DEBUG", "ERROR"]; for id in 0..3 { let tx_clone = tx.clone(); let parte_do_log = logs[id * 2..(id + 1) * 2].to_vec(); // Divide o log thread::spawn(move || { let erros = parte_do_log.iter().filter(|&&l| l == "ERROR").count(); thread::sleep(Duration::from_millis(500)); // Simula trabalho tx_clone.send(erros).unwrap(); }); } // Fecha o transmissor original para o loop do receptor terminar drop(tx); let mut total_erros = 0; for recebido in rx { total_erros += recebido; } println!("Processamento concluído. Total de erros: {}", total_erros); }
✅ Critérios de Aceite
- [ ] O programa utiliza
thread::spawncorretamente. - [ ] A comunicação entre threads é feita exclusivamente via canais (
mpsc). - [ ] O resultado final é a soma correta dos resultados parciais.
Mini-Projeto: Gerenciador de Tarefas CLI 📝
Neste projeto, você vai transformar os conceitos de CLI e manipulação de arquivos em uma ferramenta útil para o dia a dia: um gerenciador de tarefas (Todo List).
📋 Requisitos
- Interface Profissional: Use a crate
clappara gerenciar os comandos. - Comandos:
add "nome da tarefa": Adiciona uma tarefa ao arquivotarefas.txt.list: Lista todas as tarefas numeradas.
- Persistência: As tarefas devem ser salvas fisicamente no disco.
🚀 Guia de Execução
- No seu
Cargo.toml, adicione:clap = { version = "4.0", features = ["derive"] }. - Implementação sugerida:
use clap::{Parser, Subcommand}; use std::fs::{OpenOptions, read_to_string}; use std::io::Write; #[derive(Parser)] struct Cli { #[command(subcommand)] comando: Comandos, } #[derive(Subcommand)] enum Comandos { Add { tarefa: String }, List, } fn main() { let cli = Cli::parse(); match cli.comando { Comandos::Add { tarefa } => { let mut arquivo = OpenOptions::new() .append(true) .create(true) .open("tarefas.txt") .unwrap(); writeln!(arquivo, "{}", tarefa).unwrap(); println!("Tarefa adicionada!"); } Comandos::List => { let conteudo = read_to_string("tarefas.txt").unwrap_or_default(); for (i, linha) in conteudo.lines().enumerate() { println!("{}: {}", i + 1, linha); } } } }
✅ Critérios de Aceite
- [ ] O projeto utiliza a crate
clapcom macros de derivação. - [ ] As tarefas persistem após o encerramento do programa.
- [ ] O menu de
--helpé gerado automaticamente e está em português (via configurações do clap).
Mini-Projeto: API de Saudação Moderna 🌐
Vamos construir seu primeiro servidor web usando o Rust, focando em rotas dinâmicas e retorno de dados em JSON.
📋 Requisitos
- Framework: Use o
actix-web. - Rotas:
GET /: Retorna um "Bem-vindo!" em texto simples.GET /saudacao/{nome}: Retorna um JSON{"mensagem": "Olá, {nome}!"}.
- Serialização: Use a crate
serdepara gerar o JSON automaticamente.
🚀 Guia de Execução
- Adicione as dependências:
- Implementação sugerida:
use actix_web::{get, web, App, HttpServer, Responder, HttpResponse}; use serde::Serialize; #[derive(Serialize)] struct Resposta { mensagem: String, } #[get("/")] async fn index() -> impl Responder { HttpResponse::Ok().body("Bem-vindo à API Rust!") } #[get("/saudacao/{nome}")] async fn saudar(nome: web::Path<String>) -> impl Responder { let resposta = Resposta { mensagem: format!("Olá, {}!", nome), }; HttpResponse::Ok().json(resposta) } #[actix_web::main] async fn main() -> std::io::Result<()> { println!("Servidor rodando em http://localhost:8080"); HttpServer::new(|| { App::new() .service(index) .service(saudar) }) .bind("127.0.0.1:8080")? .run() .await }
✅ Critérios de Aceite
- [ ] O servidor inicia corretamente e responde na porta 8080.
- [ ] A rota de saudação retorna um JSON bem formatado.
- [ ] O código utiliza
async/awaite o atributo#[actix_web::main].
Projeto Final: Sistema de Gerenciamento de Estoque I/O 📦
O projeto final é a consolidação de tudo o que aprendemos. Você vai construir uma aplicação que gerencia o estoque de uma loja, salvando os dados em arquivo e permitindo consultas concorrentes.
📋 Requisitos Integradores
- Estruturas: Use
StructseEnumspara representar produtos e categorias. - Segurança: Implemente tratamento de erros robusto com
Result. - Concorrência: Permita que uma thread de "auditória" leia o arquivo de estoque enquanto o usuário adiciona novos itens.
- Interface: Crie uma CLI profissional usando
clap.
🛠️ Sugestão de Estrutura de Código
lib.rs: Contém a lógica de negócio (adicionar produto, salvar em arquivo, ler estoque).models.rs: Define as structs e enums do domínio.main.rs: Interface de linha de comando.
🚀 Desafios Extra (Opcional)
- [ ] Web Integration: Adicione uma pequena API Actix Web que permita consultar o estoque via navegador.
- [ ] Testes: Garanta que todas as funções críticas tenham pelo menos 80% de cobertura de testes.
🏁 Entrega
O seu repositório deve conter:
1. Arquivos .rs organizados.
2. Cargo.toml com dependências.
3. Um README.md explicando o funcionamento e como rodar o sistema.
4. Exemplos de uso (screenshots ou logs do terminal).
Quizzes
Central de Quizzes 🧠
Teste seus conhecimentos teóricos sobre a linguagem Rust com nossa bateria de quizzes interativos. Cada quiz contém 10 perguntas com explicações detalhadas ao final.
🏁 Lista de Quizzes
| Aula | Tópico | Link |
|---|---|---|
| 01 | Setup e História | Iniciar Quiz |
| 02 | Fundamentos | Iniciar Quiz |
| 03 | Controle de Fluxo | Iniciar Quiz |
| 04 | Funções e Módulos | Iniciar Quiz |
| 05 | Ownership | Iniciar Quiz |
| 06 | Borrowing | Iniciar Quiz |
| 07 | Strings e Coleções | Iniciar Quiz |
| 08 | Structs e Enums | Iniciar Quiz |
| 09 | Erros | Iniciar Quiz |
| 10 | Generics | Iniciar Quiz |
| 11 | Funcional | Iniciar Quiz |
| 12 | Qualidade (Testes) | Iniciar Quiz |
| 13 | Concorrência | Iniciar Quiz |
| 14 | CLI | Iniciar Quiz |
| 15 | Web | Iniciar Quiz |
| 16 | Final e Tendências | Iniciar Quiz |
Nota
Todos os quizzes foram atualizados para incluir as novas regras de Ownership e as tendências mais recentes do ecossistema Rust (2024/2025).
Quiz 01 - Introdução
Quiz 02 - Introdução
Quiz 03 - Introdução
Quiz 04 - Introdução
Quiz 05 - Introdução
Quiz 06 - Introdução
Quiz 07 - Introdução
Quiz 08 - Introdução
Quiz 09 - Introdução
Quiz 10 - Introdução
Quiz 11 - Introdução
Quiz 12 - Introdução
Quiz 13 - Introdução
Quiz 14 - Introdução
Quiz 15 - Introdução
Quiz 16 - Introdução
Slides
Biblioteca de Slides 🎞️
Acompanhe as aulas teóricas com nossos slides dinâmicos. Desenvolvidos em RevealJS, eles contam com animações, códigos interativos e diagramas explicativos.
📺 Slides por Aula
| Aula | Tópico | Visualizar |
|---|---|---|
| 01 | Introdução ao Rust | Abrir Slides |
| 02 | Fundamentos | Abrir Slides |
| 03 | Controle de Fluxo | Abrir Slides |
| 04 | Funções e Módulos | Abrir Slides |
| 05 | Ownership | Abrir Slides |
| 06 | Borrowing | Abrir Slides |
| 07 | Strings e Coleções | Abrir Slides |
| 08 | Structs e Enums | Abrir Slides |
| 09 | Erros | Abrir Slides |
| 10 | Generics | Abrir Slides |
| 11 | Funcional | Abrir Slides |
| 12 | Testes e Docs | Abrir Slides |
| 13 | Concorrência | Abrir Slides |
| 14 | Projeto CLI | Abrir Slides |
| 15 | Web | Abrir Slides |
| 16 | Final e Tendências | Abrir Slides |
Dica de Teclado
Ao abrir os slides, use as setas do teclado ou Espaço para navegar. Pressione 'f' para tela cheia e 'o' para visão geral.
Aula 01 - Introdução a Microsserviços 🌐
De Monólitos a Sistemas Distribuídos
Agenda de Hoje 📅
- Panorama do Software Moderno
- Monólitos vs Microsserviços
- A Economia das APIs
- Escalabilidade Vertical vs Horizontal
- Cinto de Utilidades (Ferramentas)
- Setup do Ambiente
1. O Mundo Cloud-Native ☁️
- Sistemas globais exigem disponibilidade 24/7.
- Milhões de requisições por segundo.
- Deploy contínuo (várias vezes ao dia).
2. A Evolução da Arquitetura 🏛️➡️🏗️
2.1 O Monólito 🏛️
- Um único projeto, um único deploy.
- Tudo ou nada: erro em um lugar afeta tudo.
- Difícil de escalar partes específicas.
- Ideal para: Projetos pequenos, MVPs rápidos.
2.2 Microsserviços 🏗️
- Conjunto de serviços independentes.
- Comunicação via rede (APIs).
- Cada um com seu banco de dados.
- Ideal para: Sistemas complexos e escaláveis.
3. O Papel das APIs 📡
- Contract-First: Acordo de comunicação.
- REST como padrão dominante.
- JSON: A língua universal.
Escalabilidade: Vertical vs Horizontal
| Vertical (Scale Up) | Horizontal (Scale Out) |
|---|---|
| Aumenta CPU/RAM | Adiciona mais servidores |
| Tem limite físico | Virtualmente ilimitada |
| Causa downtime no upgrade | Zero downtime (Redundância) |
Arquitetura de Microsserviços
graph LR
User[Cliente] --> AGW[API Gateway]
AGW --> S1[Usuários]
AGW --> S2[Pedidos]
AGW --> S3[Pagamentos]
S1 --> DB1[(DB)]
S2 --> DB2[(DB)]
S3 --> DB3[(DB)]
4. Ferramentas Indispensáveis 🛠️
Client HTTP: Postman & Insomnia
- Testar rotas sem Frontend.
- Analisar Headers e Status Codes.
- Simular diferentes cenários de erro.
Containerização: Docker 🐋
- "Roda na minha máquina, roda em qualquer lugar".
- Isola dependências e versões.
- Facilita a subida de múltiplos serviços locais.
5. Estrutura de Projeto Backend 📂
- Divisão clara de responsabilidades.
- Controllers, Services e Repositories.
- Tratamento global de exceções.
6. Setup do Ambiente 🚀
Requisitos:
- IDE: VS Code ou IntelliJ.
- Postman (Desktop ou Extensão).
- Docker Desktop.
- Git & GitHub.
Resumo da Aula ✅
- Microsserviços trazem resiliência e escala.
- APIs são o coração da comunicação moderna.
- Ferramentas como Docker mudaram o jogo.
- Começamos nossa jornada Fullstack!
Próxima Aula: Arquitetura e Gateway 🏗️
- Como os serviços conversam?
- O que é Service Discovery?
- Protegendo a porta de entrada.
Dúvidas? 🤔
"A arquitetura de hoje é o legado de amanhã. Escolha com sabedoria."
Aula 02 - Arquitetura e Gateway 🏗️
Orquestrando Microsserviços
Agenda 📅
- Comunicação entre Serviços
- Síncrono vs Assíncrono
- O Papel do API Gateway
- Service Discovery
- Load Balancing
- Padrões de Resiliência
1. Como os Serviços Conversam? 💬
- Microsserviços são ilhas que precisam de pontes.
- Dois mundos: Sync e Async.
1.1 Comunicação Síncrona 🔄
- Cliente bloqueia até a resposta.
- Uso de HTTP/REST ou gRPC.
- Risco: Acoplamento temporal e gargalos.
1.2 Comunicação Assíncrona 📬
- Envia e esquece (Eventos).
- Uso de Filas e Tópicos (Broker).
- Vantagem: Escalabilidade e desacoplamento.
2. API Gateway: O Porteiro 🚪
- Única entrada para o mundo exterior.
- Esconde a complexidade interna.
Gateway Responsibilities
- Roteamento:
/p-> Pagamento,/e-> Estoque. - Segurança: Autenticação centralizada.
- Rate Limit: Proteção contra flood.
- Logs & Monitoramento.
3. Service Discovery 🔎
- Onde está o servidor de pagamentos?
- Agenda dinâmica de IPs e Portas.
- Ferramentas: Netflix Eureka, Consul.
4. Load Balancing ⚖️
- Distribuição inteligente da carga.
- Evita que um container "morra" de trabalho.
graph TD
GW[Gateway] --> LB[Load Balancer]
LB --> S1[Serviço A]
LB --> S2[Serviço B]
LB --> S3[Serviço C]
5. Resiliência: Circuit Breaker 🔌
- Detecta serviços lentos ou falhos.
- Abre o circuito para proteger o resto do sistema.
- Evita o cascateamento de erros.
Comparativo: Sync vs Async
| Característica | Síncrono 🔄 | Assíncrono 📬 |
|---|---|---|
| Resposta | Imediata | Eventual |
| Desempenho | Limitado pelo destino | Alto débito |
| Uso comum | Cadastro/Login | Geração de Relatórios |
6. Prática: O "Dashboard" Agregador 💻
- Como o Gateway une dados de 3 serviços?
- Agregação de respostas (Aggregation Pattern).
Desafio Relâmpago ⚡
O que acontece se o seu API Gateway cair? Ele é um ponto único de falha?
Resumo ✅
- Sync é fácil, Async é escalável.
- API Gateway protege e organiza.
- Service Discovery é essencial em containers.
- Resiliência não é opcional!
Próxima Aula: Modelagem REST 📡
- Verbos HTTP.
- Status Codes.
- O contrato ideal.
Dúvidas? 🏗️
Aula 03 - Modelagem de APIs RESTful 📡
Recursos, Verbos e Contratos
Agenda 📅
- O que é REST?
- Recursos e URIs
- Verbos HTTP (GET, POST, PUT...)
- Status Codes
- JSON: A Linguagem das APIs
- Boas Práticas de Design
1. REST: A "Língua" da Web 🌐
- Style arquitetural para sistemas distribuídos.
- Baseado no protocolo HTTP.
- Independência entre Client e Server.
Princípios REST
- Stateless: Cada requisição é única.
- Uniform Interface: Padrões compartilhados.
- Cacheable: Melhore a performance.
2. Identificando Recursos 📍
- Um recurso é qualquer coisa que expomos.
- URI: O endereço do recurso.
O que NÃO fazer:
GET /obterUsuarios ❌
O que fazer:
GET /usuarios ✅ (Sempre substantivos no plural!)
3. Os Verbos HTTP 🛠️
Eles definem a intenção da chamada:
- GET: Buscar dados.
- POST: Criar novo dado.
- PUT: Atualizar (Trocar tudo).
- PATCH: Atualizar (Apenas um pedaço).
- DELETE: Remover dado.
Idempotência e Segurança
| Verbo | Seguro? | Idempotente? |
|---|---|---|
| GET | Sim ✅ | Sim ✅ |
| POST | Não ❌ | Não ❌ |
| PUT | Não ❌ | Sim ✅ |
| DELETE | Não ❌ | Sim ✅ |
4. Status Codes: A Resposta 🚦
- 2xx: Deu certo! (200, 201, 204).
- 4xx: Você (cliente) errou algo (400, 401, 404).
- 5xx: Eu (servidor) quebrei (500, 503).
5. O Formato JSON 🏗️
- Leve, legível e universal.
6. Design de URIs Complexas
Como buscar os pedidos de um usuário específico?
GET /usuarios/123/pedidos ✅
- Hierarquia lógica e limpa.
7. Prática: Postman em Ação 💻
- Testando verbos em APIs reais.
- Analisando Headers e Body.
Desafio REST ⚡
Se você quer mudar apenas o e-mail de um usuário, qual verbo deve usar: PUT ou PATCH?
Resumo ✅
- REST é sobre recursos e padrões.
- URIs usam substantivos no plural.
- Status codes guiam o frontend.
- JSON é o padrão de facto.
Próxima Aula: Swagger e Mocks 📝
- Documentação automática.
- Como trabalhar sem o backend pronto?
Dúvidas? 📡
Aula 04 - Documentação e Mocks 📝
Developer Experience e Contratos
Agenda 📅
- Por que documentar?
- OpenAPI vs Swagger
- Swagger UI e Editor
- O Poder dos Mocks
- Developer Experience (DX)
- Ferramentas de Simulação
1. Documentação é DX 🚀
- Sua API é seu produto.
- Documentar economiza tempo de suporte.
- Facilita a integração com Front/Mobile.
2. OpenAPI (OAS) 📜
- O padrão mundial.
- Arquivo YAML ou JSON descritivo.
- Agnóstico de linguagem.
3. Swagger: O Canivete Suíço 🛠️
- Editor: Escreva e valide o contrato.
- UI: Gere a página visual de testes.
- Codegen: Gere código (client/server) automaticamente.
Swagger UI em Ação
- Permite testar endpoints no próprio navegador.
- Mostra exemplos de JSON de entrada e saída.
- Exibe todos os Status Codes possíveis.
4. O Poder dos Mocks 🎭
- Development in Parallel: Front não espera pelo Back.
- Servidor "Fake" que retorna dados reais.
- Valide a experiência antes da implementação complexa.
5. Developer Experience (DX) 👨💻
Como ser amado por outros devs:
- Nomes de rotas claros.
- Erros descritivos no Body.
- Exemplos de requisição.
- Documentação atualizada (ou gerada pelo código).
6. Ferramentas Recomendadas 🧰
- Swagger Editor: Online ou Local.
- Mockoon: Mock local amigável.
- Prism: Mock via CLI.
- Postman: Collections documentadas.
7. Prática: Editando um YAML 💻
- Desenhando um endpoint
GET /tarefas. - Definindo parâmetros de entrada.
- Criando esquemas de dados.
Desafio: Mock vs Stubs ⚡
Qual a principal vantagem de um Mock Server online (como Postman) em relação a um Mock rodando apenas no computador do desenvolvedor?
Resumo ✅
- OpenAPI é o contrato.
- Swagger UI é a vitrine da sua API.
- Mocks destravam o desenvolvimento da equipe.
- DX é o diferencial de uma boa API.
Próxima Aula: Implementação Backend! 💻
Módulo 2: Manipulação de Dados
- Controllers e Services.
- Repositories e Banco de Dados.
- Mão na massa com código real!
Dúvidas? 📝
Aula 05 - Implementação de APIs ⚙️
Controllers e Rotas
Agenda 📅
- Camadas do Backend
- O Papel do Controller
- Rotas e Handlers
- Capturando Dados (Params/Body)
- Status Codes na Prática
- Injeção de Dependência
1. Organização em Camadas 🧱
- Controller: Trata a entrada (HTTP).
- Service: Regras de negócio.
- Repository: Acesso ao banco.
2. O Papel do Controller 🎮
- Ele é o ponto de entrada.
- Não deve ter lógica complexa!
- Deve apenas orquestrar a execução.
Controller = Garçom 🤵 Service = Cozinheiro 👨🍳
3. Rotas e Handlers 📍
- Rota: Verbo HTTP + Path.
- Handler: Função executada.
4. Capturando Dados 📥
- Path Params:
/id/123(Identificação). - Query Params:
?q=busca(Filtro). - Body: Enviando JSON (Criação/Update).
5. Respostas de Qualidade 📤
- Nunca esqueça o Status Code!
- Sucesso: 200, 201, 204.
- Erro: 400, 401, 404, 500.
6. Injeção de Dependência 💉
- Receber serviços prontos.
- Facilita testar o Controller "isolado".
7. Prática: O Primeiro Endpoint 💻
- Mapeando um
GET /ping. - Retornando um
pongem JSON. - Testando no Insomnia/Postman.
Desafio: Params vs Query ⚡
Se você quer listar todos os alunos de uma sala com o nome "Pedro", qual tipo de parâmetro você usaria para o nome?
Resumo ✅
- Controllers são a porta de entrada.
- Devem ser leves e objetivos.
- Capturam dados e retornam status/JSON.
- Seguem as rotas definidas.
Próxima Aula: Regras de Negócio! 🧠
Services e Validações
- Onde o cálculo acontece.
- Isolando o código do "mundo externo".
Dúvidas? ⚙️
Aula 06 - Services e Regras de Negócio 🧠
O Cérebro da Aplicação
Agenda 📅
- Por que separar as coisas?
- Responsabilidades do Service
- O Fluxo: Controller -> Service
- Tratamento de Erros Profissional
- DTOs: Protegendo os Dados
- Service vs ViewModel (Mobile)
1. O Problema: "Controller Gordo" 🍔
- Lógica de negócio misturada com HTTP.
- Código impossível de reutilizar.
- Difícil de testar.
2. A Solução: Layered Architecture 🧱
- Controller: Trata o transporte (HTTP).
- Service: Trata a regra (O QUE fazer).
3. O que vai no Service? ⚖️
- Validações complexas.
- Cálculos de valores.
- Envio de e-mails/notificações.
- Integração com repositórios.
4. Tratamento de Erros ⚠️
- O Service Lança (Throws).
- O Controller Captura (Catches).
// Service
if (!saldo) throw new Error("Saldo Insuficiente");
// Controller
try { ... } catch (e) { res.status(400)... }
5. DTOs: Filtrando a Saída 📦
- Nunca envie "tudo" do banco para o cliente.
- Proteja campos sensíveis (Ex:
senha_hash). - Melhore a performance (menos dados trafegados).
6. Service vs ViewModel 🆚
- No Backend: Service é o cérebro.
- No Mobile/Front: ViewModel é o cérebro.
- Ambos servem para "limpar" a camada de visualização.
7. Prática: Validando um Cadastro 💻
- Verificando se o e-mail é válido.
- Verificando se o usuário já existe.
- Lançando erros específicos.
Desafio: Onde colocar? ⚡
Se uma regra diz: "Usuários VIP ganham 20% de desconto", essa regra deve ficar no Controller ou no Service?
Resumo ✅
- Controllers recebem, Services processam.
- Mantenha seus Controllers "finos" (Slim Controllers).
- Centralize as regras para facilitar a manutenção.
- DTOs são as fronteiras dos dados.
Próxima Aula: Onde os dados vivem! 🗄️
Repositories e Banco de Dados
- PostgreSQL e SQL básico.
- Camada de persistência.
Dúvidas? 🧠
Aula 07 - Repositories e Banco de Dados 🗄️
Onde a informação descansa
Agenda 📅
- Por que Bancos de Dados?
- PostgreSQL: O Robusto
- SQL Básico (SELECT, INSERT...)
- Relacionamentos (1:N, N:N)
- Camada de Persistence
- O Padrão Repository
1. Persistência de Dados 💾
- Sem banco, o servidor esquece tudo ao reiniciar.
- Precisamos de segurança e integridade.
- Estritamente Tipado: O banco garante o formato.
2. Por que PostgreSQL? 🐘
- Código Aberto (Open Source).
- Extremamente confiável (ACID).
- Suporta dados complexos (JSONB).
3. SQL: A Linguagem Universal 🗣️
- DDL: Define a estrutura (Tabelas).
- DML: Manipula os dados (Linhas).
4. O Coração: Relacionamentos 🔗
- 1:N: Um cliente, muitos pedidos.
- N:N: Muitos alunos, muitos cursos.
- Foreign Key: A âncora que liga tudo.
5. Camada de Persistence 🧱
- O código que conversa com o driver do banco.
- Onde as queries são traduzidas para o código.
6. Padrão Repository 📥
- "Não me diga como, diga O QUE você quer".
- Isola o SQL da regra de negócio.
7. Migrations 📜
- Controle de versão para o Banco.
- Permite "voltar no tempo" se algo quebrar.
- Mantém o time em sincronia.
Desafio SQL ⚡
Qual comando você usaria para mudar o preço de todos os produtos da categoria 'Games' para 99.90?
Resumo ✅
- Bancos de dados dão memória ao sistema.
- PostgreSQL é o padrão da indústria.
- SQL é habilidade obrigatória para backend.
- Repository Pattern traz flexibilidade.
Próxima Aula: Integridade! ✅
Validação e Boas Práticas
- Garantindo que dados "sujos" não entrem no banco.
- Tratamento de exceções de banco.
Dúvidas? 🗄️
Aula 08 - Boas Práticas e Validação ✅
Qualidade e Segurança no Backend
Agenda 📅
- Por que Validar Tudo?
- Validação vs Sanitização
- Schema Validation (Ex: Zod)
- Clean Code (Código Limpo)
- Tratamento de Erros Profissional
- Middlewares Globais
1. Regra de Ouro: Desconfiança 🛡️
- O cliente é o "lado perigoso" da aplicação.
- Validações evitam dados corrompidos.
- Defesa em Profundidade: Garanta a regra no banco E no código.
2. Validar vs Sanitizar 🧼
- Validar: Checar (Idade > 18?).
- Sanitizar: Limpar (Remover
<script>).
3. Schema Validation 📐
- Crie "moldes" para seus dados.
- Validação centralizada e reutilizável.
4. O Backend Elegante (Clean Code) ✨
- DRY: Don't Repeat Yourself (Não repita lógica).
- KISS: Keep It Simple, Stupid (Mantenha o simples).
- Nomes de funções que explicam o que está acontecendo.
5. Tratamento de Erros 🚨
- Controller trata o fluxo, não o detalhe técnico.
- Try/Catch Global: Evite crashes.
- Mensagens amigáveis para o cliente.
6. Logs vs Mensagens 📜
- Terminal/Log: Detalhe técnico completo.
- Cliente (JSON): Apenas o que ele precisa saber.
"Ocorreu um erro interno" (Cliente) ✅ "Query failed at line 42 due to NULL constraint" (Logs) ✅
7. Prática: O Schema Perfeito 💻
- Validando um produto complexo.
- Tratando erros de tipo (String no lugar de Number).
Desafio: Limpeza ⚡
Se você recebe um texto de um post com muitos espaços em branco no final, você deve Validar ou Sanitizar?
Resumo ✅
- Backend robusto exige validação rigorosa.
- Limpe os dados antes de salvar (Sanitize).
- Middleware Global centraliza a gestão de falhas.
- Código limpo economiza meses de manutenção.
Próxima Aula: Módulo 3! 🔐
Segurança e Autenticação
- Quem é você? (Authentication).
- O que você pode fazer? (Authorization).
Dúvidas? ✅
Aula 09 - Segurança e Autenticação com JWT 🔐
Portas trancadas e Crachás Digitais
Agenda 📅
- Autenticação vs Autorização
- O Fim das Sessões (Stateful)
- O que é JWT?
- Estrutura: Header, Payload, Signature
- Fluxo de Login completo
- Melhores Práticas de Segurança
1. Quem é Você? (Autenticação) 🚦
- Validar a identidade do usuário.
- Login e Senha.
- Autorização: O que você PODE fazer? (Níveis de acesso).
2. Por que JWT? 🤔
- Abordagem Stateless (Sem estado).
- O servidor não guarda sessão na memória (escalável!).
- Perfeito para Microserviços e Mobile.
3. Estrutura do Token 🎫
- Header: Algoritmo (ex: HS256).
- Payload: Os dados (id, role, nome).
- Signature: O lacre de segurança.
4. O Coração do JWT: A Assinatura 🖋️
- Usa uma
SECRET_KEYno servidor. - Garante que o token não foi "hackeado" ou alterado.
5. Fluxo de Login 🌊
- Envia credenciais -> 2. Servidor valida -> 3. Gera JWT -> 4. Frontend guarda o Token -> 5. Envia no Header em cada requisição.
6. Segurança em Mobile 📱
- Nunca guarde em arquivos de texto!
- Use EncryptedSharedPreferences (Android) ou Keychain (iOS).
7. Melhores Práticas 🏆
- Use chaves secretas longas e seguras.
- Defina tempo de expiração (
expiresIn). - Protocolo HTTPS é obrigatório!
Desafio de Segurança ⚡
O Payload do JWT é criptografado ou apenas codificado? Posso guardar a senha do usuário lá?
Resumo ✅
- JWT permite autenticação rápida e escalável.
- Header + Payload + Signature.
- Stateless = Servidor mais leve.
Próxima Aula: Controle de Acesso 🛡️
Quem manda aqui? (RBAC)
- Middlewares de autorização.
- Protegendo rotas por nível de usuário.
Dúvidas? 🔐
Aula 10 - Controle de Acesso (RBAC) 🛡️
Hierarquia e Segurança em Camadas
Agenda 📅
- O que é RBAC? (Roles)
- Autenticação vs Autorização
- O Fluxo do Middleware
- Erros 401 vs 403
- Protegendo rotas na prática
- Hierarquia de Perfis
1. Role-Based Access Control 👑
- Permissões ligadas a Perfis (Roles).
- Ex: ADMIN, EDITOR, VIEWER.
- Facilita a gestão de milhares de usuários.
2. A Cancela (Middleware) 🚧
- O middleware checa se o usuário tem a "chave" certa.
- Se não tiver -> 403 Forbidden.
- Se tiver ->
next().
3. O Fluxo de Segurança 🌊
graph LR
Req[Request] --> Auth[Autenticação]
Auth --> |OK| Role[Autorização]
Role --> |OK| Controller[Recurso Final]
4. 401 vs 403: Não confunda! ❌
- 401 (Unauthorized): "Quem é você?". Token inválido ou ausente.
- 403 (Forbidden): "Eu sei quem você é, mas não deixo entrar". Falta de permissão.
5. Implementação Dinâmica 🔒
// Middleware genérico
router.delete('/usuario/:id',
autenticar,
autorizar(['ADMIN']),
userController.remover
);
6. Hierarquia de Acesso 🏛️
- Um Admin deve poder acessar rotas de User?
- Design de sistema: Roles "Pai" e "Filho".
7. Melhores Práticas 🏆
- Centralize a lógica em Middlewares.
- Nunca exponha permissões sensíveis no frontend (segurança do lado do servidor).
Desafio: Segurança ⚡
Em um sistema escolar, o Diretor e o Professor podem ver notas. O Aluno só vê as dele. Como você configuraria a Role da rota GET /notas?
Resumo ✅
- RBAC organiza permissões por grupos.
- Middlewares são os guardiões das rotas.
- Diferenciar 401 de 403 é vital para Debug.
Próxima Aula: Segurança Avançada 🏗️
Session vs Token e Refresh Tokens
- O que fazer quando o token expira?
- Protegendo contra ataques comuns (XSS, CSRF).
Dúvidas? 🛡️
Aula 11 - Refresh Token e Segurança Avançada 🏗️
Blindando sua API contra o mundo
Agenda 📅
- O Problema do Token Curto ⏰
- Refresh Tokens (O que são?)
- CORS: Origens e Destinos
- Helmet: Headers de Aço
- Rate Limit: Contra Brute Force
- Ataques Comuns (XSS, Injection)
1. Por que Tokens Expiram? ⏰
- Segurança! Se roubarem o token, ele dura pouco.
- Problema: O usuário odeia fazer login toda hora.
2. Refresh Token 🔁
- Um token de longa duração (7 dias+).
- Serve apenas para trocar por um novo Access Token.
- Deve ser invalidado se o usuário deslogar.
3. CORS: Cross-Origin Resource Sharing 🌍
- "Quem pode me chamar?".
- Resolvido via Headers no Servidor.
- Nunca use
origin: '*'em ambientes reais!
4. Helmet: Proteção de Headers 🪖
- Remove o
X-Powered-By(não diz que é Express). - Adiciona proteção contra Clickjacking e XSS.
5. Rate Limiting 🔨
- 5 tentativas de login por minuto? Sim.
- Evita que robôs tentem descobrir senhas via "força bruta".
6. Onde salvar os Tokens? 🛡️
- Frontend: LocalStorage? Seguro?
- Melhor Prática: Cookies
HttpOnly+Secure.
7. Melhores Práticas de Segurança 🏆
- Use HTTPS sempre.
- Valide TODAS as entradas do usuário.
- Mantenha as bibliotecas atualizadas.
Desafio de Segurança ⚡
Qual a diferença entre 401 e 403 no contexto de Refresh Tokens? Se eu recebo 401, eu tento o refresh ou deslogo o usuário?
Resumo ✅
- Refresh Token equilibra UX e Segurança.
- CORS e Helmet são as portas do seu castelo.
- Proteja-se contra robôs com Rate Limit.
Próximo Módulo: Front-End Moderno 🎨
Saindo das APIs e indo para a Web!
- Introdução ao React/Vite.
- Consumindo nossas APIs no navegador.
Dúvidas? 🏗️
Aula 12 - Introdução ao React ⚛️
O Poder dos Componentes Modernos
Agenda 📅
- O que são SPAs?
- Por que React?
- Vite: A Ferramenta Rápida
- JSX: JS + HTML
- Componentes e LEGO
- Props: O Coração Dinâmico
1. Single Page Applications (SPA) 📄
- O site que nunca recarrega.
- Navegação fluida e instantânea.
- Ex: Gmail, Facebook, Spotify Web.
2. Por que o React venceu? ⚔️
- Componentização (Foco no Reuso).
- Virtual DOM (Foco na Performance).
- Gigantesco Ecossistema (Foco no Emprego).
3. Vite: O Novo Padrão ⚡
- Inicia o projeto em segundos.
- Feedback instantâneo durante o código.
4. JSX: A Mistura Perfeita 🧪
- Parece HTML, mas tem o poder do Javascript.
5. Componentes = LEGO 🧩
- Pequenas partes isoladas.
- Facilita testes e trabalho em equipe.
6. Props: Passando o Bastão 🎁
- Permite que componentes recebam dados do "pai".
- Torna componentes genéricos e reutilizáveis.
Resumo ✅
- SPA torna a Web parecida com Apps.
- React organiza sua UI em componentes.
- Vite é seu melhor amigo no desenvolvimento.
Próxima Aula: Dinâmica e Estado 🎣
O que acontece quando o usuário clica?
- Hooks:
useState. - Reatividade na prática.
Dúvidas? ⚛️
Aula 13 - Estado e Hooks 🎣
Tornando seu App Interativo
Agenda 📅
- O que é o Estado (State)?
- Hook
useState - Lidando com Cliques e Eventos
- Inputs Controlados
- Imutabilidade e Arrays
1. O Problema da Estática 🧱
- Variáveis comuns mudam nos bastidores...
- ...mas a tela continua a mesma!
- O React precisa de um sinal para re-desenhar.
2. useState: O Motor de Mudança 🚀
- cont: O valor atual.
- setCont: A função que atualiza.
- 0: O ponto de partida.
3. Eventos no React ⚡
onClick={funcao}onChange={(e) => ...}- Sempre em CamelCase!
4. Inputs Controlados ⌨️
- O React é quem manda no valor do input.
value={estado}+onChange.- Facilita validação e limpeza de campos.
5. Imutabilidade (Muito Importante!) 💎
- Nunca altere o estado original:
lista.push(x)❌ - Sempre crie uma cópia nova:
setLista([...lista, x])✅
6. Fluxo de Dados 🌊
- O estado flui do Pai para o Filho via Props.
- Se o estado do Pai muda, todo mundo abaixo dele atualiza.
Desafio de Estado ⚡
Se eu tenho um botão que soma +1 ao contador, o que acontece com a interface se eu esquecer de importar o useState e usar uma variável global let contador = 0?
Resumo ✅
useStatetraz vida aos componentes.- Mudança de estado = Re-renderização.
- Use sempre funções disparadoras (
set...).
Próxima Aula: Efeitos e APIs 🌐
Buscando dados no mundo real!
- Hook:
useEffect. - Consumindo nossa API Backend.
Dúvidas? 🎣
Aula 14 - Efeitos e APIs 🌐
Conectando seu App ao Mundo Real
Agenda 📅
- O que são Side Effects?
- Hook
useEffect - O Array de Dependências
- Buscando dados com
fetch - Estados de Carregamento e Erro
1. Além da Interface 🧪
- Efeitos colaterais são ações que tocam o mundo externo ao componente.
- Ex: Buscar usuários, mudar o título da aba, iniciar um cronômetro.
2. useState vs useEffect 🥊
- useState: Para dados que o usuário vê mudando.
- useEffect: Para ações que o componente faz "sozinho".
3. Os 3 Momentos do useEffect 🕒
- Montagem: Quando o componente nasce.
- Atualização: Quando um dado monitorado muda.
- Desmontagem: Quando o componente morre (Cleanup).
4. O Array de Dependências [] 🗃️
[]-> Roda só uma vez.[cont]-> Roda sempre quecontmudar.Sem array-> Roda em toda atualização (Perigo!).
5. Chamadas de API (Fetch) 📨
useEffect(() => {
fetch("https://api...")
.then(res => res.json())
.then(data => setData(data));
}, []);
6. UX: Estados de Rede 🛡️
- Loading: Mostre um Spinner enquanto espera.
- Error: Avise se a internet caiu ou o usuário não existe.
- Empty: Diga se não há resultados.
Desafio de Efeito ⚡
Se você colocar um alert("Olá") dentro de um useEffect sem o array [], quantas vezes o alerta vai aparecer se o usuário ficar digitando em um campo de texto que atualiza o estado?
Resumo ✅
useEffectorganiza as ações assíncronas.- Controle quando rodar via array de dependências.
- Trate sempre o carregamento e erros para uma boa UX.
Próxima Aula: Navegação 🚦
Multi-páginas com React Router!
/home,/perfil,/contato.- Links e Navegação Programática.
Dúvidas? 🌐
Aula 15 - React Router 🚦
Criando Apps Multi-Página
Agenda 📅
- O que são SPAs?
- Multi-páginas (Simuladas)
- Componentes de Rota
- Navegação (
LinkeuseNavigate) - Parâmetros dinâmicos (
:id)
1. O Mundo do SPA ⚛️
- O site é uma única página HTML.
- O Javascript "troca" a tela sem recarregar.
- UX rápida e fluida.
2. React Router Dom ⚙️
- A biblioteca padrão para web.
- Permite que a URL combine com o que aparece na tela.
3. A Estrutura Básica 🏗️
- BrowserRouter: O container principal.
- Routes: O seletor de rotas.
- Route: Define o caminho (
path) e o componente (element).
4. Navegando sem Recarregar! 🏃♂️
- Use
<Link to="/contato"> - NUNCA use
<a href="...">para rotas internas.
5. Navegação Programática 🚀
- Ideal para redirecionar após ações (Login, Clique em Card).
6. Rotas Dinâmicas (URL Params) 🆔
path="/perfil/:username"- Hook
useParams()captura o valor. - Uma única página que se adapta a mil perfis.
7. Página 404 (Not Found) 👻
path="*"- Garante que o usuário nunca caia em uma tela em branco.
Desafio de Roteamento ⚡
Se eu digitar www.meusite.com/asdfg e não tiver uma rota configurada para isso, o que o usuário vai ver se eu NÃO colocar uma rota com o path="*"?
Resumo ✅
- Roteamento traz a sensação de um site real.
- Hooks
useNavigateeuseParamssão essenciais. - SPAs são o padrão da indústria moderna.
Próxima Aula: O Grande Final 🏆
Projeto Integrado: Backend + Frontend!
- Conectando nossa API Node ao site React.
- O Projeto Final do Curso!
Dúvidas? 🚦
Aula 16 - Projeto Final e Conclusão �
De aluno a Desenvolvedor Full-Stack
Agenda 📅
- O Desafio Final 🔗
- Requisitos Técnicos
- Portfólio no GitHub
- Onde continuar estudando?
- Mensagem de Encerramento
1. O Desafio Final 🚀
Você deve entregar um projeto integrado contendo: - Frontend: SPA em React com rotas. - Backend: API segura em Node.js. - Integração: Conexão real entre os dois. - Design: CSS moderno e responsivo.
2. Sugestões de Temas 💡
- Gerenciador de Tarefas �
- Mini E-commerce 🛒
- Rede Social Simplificada 💬
- Dashboard de Monitoramento 📊
3. O README de Elite ✨
- Prints ou Vídeos do site funcionando.
- Lista detalhada de tecnologias.
- Guia: "Como rodar o Projeto".
4. Onde ir agora? 📚
- TypeScript: Segurança de tipos.
- Bancos SQL: Postgres e MySQL.
- Next.js: O rei do mercado React.
- Docker: Infraestrutura moderna.
5. Soft Skills 🤝
- Não é só saber programar!
- Trabalho em equipe.
- Resolução de problemas reais.
6. O Mercado Full-Stack 📈
- Demanda altíssima por devs completos.
- Salários excelentes.
- Dashboards e Sistemas Web movem o mundo!
7. Mensagem Final 🌟
"Programar é a arte de criar soluções onde antes só havia problemas."
- Você construiu a base sólida.
- O código é sua ferramenta de transformação.
Parabéns pela Jornada! 🎓🚀
Vá e construa o futuro da Web.
Dúvidas Finais? 🤔
Configuração
Ambientes de Desenvolvimento 🛠️
Guias para configurar seu computador para o desenvolvimento mobile.
-
Android --- Instalação do Android Studio, SDK e emuladores.
-
iOS (Opcional/Referência) --- Configuração básica de Xcode e ferramentas Mac.
-
Ferramentas de Apoio --- Git, Terminais e Postman/Insomnia para testes de API.
Setup 01: Android Studio 🤖
O Android Studio é a IDE oficial para o desenvolvimento Android.
1. Requisitos de Sistema
- RAM: Mínimo 8GB (Sugerido 16GB+).
- Espaço: Mínimo 10GB para IDE + SDKs.
- Processador: Intel Core i5 ou equivalente.
2. Instalação
- Acesse o site oficial: developer.android.com/studio.
- Baixe a versão mais recente para o seu Sistema Operacional.
- Execute o instalador e escolha a opção "Standard" na configuração inicial.
3. Configurando o SDK
- Após a instalação, vá em Settings > Languages & Frameworks > Android SDK.
- Certifique-se de que a versão mais recente do Android (estável) esteja instalada.
- Na aba SDK Tools, instale o "Android Emulator" e o "Intel x86 Emulator Accelerator (HAXM)" se estiver no Windows com Intel.
4. Criando um Emulador (AVD)
- Abra o Device Manager.
- Clique em Create Device.
- Escolha um dispositivo (ex: Pixel 7).
- Selecione uma imagem de sistema (ex: Level 34 - Android 14).
- Finalize e clique no "Play" para iniciar o celular virtual.
5. Solução de Problemas ⚠️
- VT-x is disabled: Você precisa habilitar a virtualização na BIOS do seu computador.
- Studio muito lento: Adicione a pasta do projeto e as pastas do Android SDK nas exclusões do seu Antivírus.
Setup 02: Xcode (iOS Foundation) 🍎
O Xcode é a ferramenta necessária para compilar e testar apps iOS.
[!IMPORTANT] O Xcode requer um computador Mac (macOS).
1. Instalação
- Abra a App Store no seu Mac.
- Pesquise por Xcode.
- Clique em Obter/Instalar.
- Após o download, abra o Xcode para carregar os componentes adicionais do macOS.
2. Configurando Simuladores
- Vá em Settings > Platforms.
- Verifique se o componente "iOS" está baixado.
- Se não estiver, clique em "GET" para baixar a versão mais estável.
3. Comandos de Linha (CLI)
Para que ferramentas de automação funcionem, você precisa instalar os Command Line Tools:
4. Opcional: CocoaPods
Muitos projetos iOS antigos ainda usam CocoaPods para dependências:
5. Solução de Problemas ⚠️
- Espaço em Disco: O Xcode é muito grande. Garanta pelo menos 40GB de espaço livre para ele e os simuladores.
- Build Lento: Use simuladores de modelos mais simples (ex: iPhone SE) para poupar memória RAM se necessário.
Setup 03: Ferramentas de Apoio 🛠️
Além da IDE, você precisará de ferramentas para gerenciar código e testar dados.
1. Git e GitHub
Essencial para versionamento. * Download: git-scm.com. * Configuração Inicial:
2. Postman ou Insomnia
Para testar as APIs REST antes de escrever código Kotlin/Swift. * Postman: postman.com. * Insomnia: insomnia.rest.
3. Vysor (Opcional)
Para espelhar a tela do seu celular real no computador (via cabo USB). * Acesso: vysor.io.
4. ADB (Android Debug Bridge)
Já vem com o Android Studio, mas é útil no PATH do sistema.
* Permite instalar APKs via terminal: adb install app.apk.
* Permite ver logs detalhados: adb logcat.
5. Flipper (Meta)
Uma ferramenta avançada para debugar bancos de dados SQLite e chamadas de rede direto na interface visual. * Acesso: fbflipper.com.
Setup 04: Java e JDK ☕
1. JDK (Java Development Kit)
O kit essencial para compilar Java.
1. Baixe o JDK 17 LTS (ou 21 LTS) no site da Oracle ou Adoptium.
2. Instale e configure a variável de ambiente JAVA_HOME.
3. Teste: java -version.
2. IntelliJ IDEA (Recomendado)
A melhor IDE para Java/Kotlin. 1. Baixe a versão Community (Gratuita) em jetbrains.com/idea. 2. Instale.
3. VS Code
Se preferir o VS Code: 1. Instale o "Extension Pack for Java" da Microsoft.
4. Solução de Problemas Comuns ⚠️
- 'javac' não reconhecido: A variável de ambiente
JAVA_HOMEou oPathestão errados. Verifique se apontam para a pastabindo JDK. - Erro: "Class names are only accepted...": O nome do arquivo DEVE ser igual ao nome da classe (ex:
Ola.javatem que terpublic class Ola). - Versão antiga do Java: Digite
java -versionpara conferir se está usando a versão que acabou de instalar.
Setup 05: .NET (C# e F#) 🔷
1. .NET SDK
Necessário para rodar C# e F#.
1. Baixe o .NET 8.0 SDK (LTS) em dotnet.microsoft.com.
2. Instale.
3. Teste: dotnet --version.
2. Visual Studio Community
A IDE mais completa para Windows. 1. Baixe em visualstudio.microsoft.com. 2. No instalador, selecione a carga de trabalho: "Desenvolvimento para desktop com .NET".
3. VS Code + C# Dev Kit
Para uma experiência mais leve: 1. Instale a extensão "C# Dev Kit" da Microsoft.
4. Solução de Problemas Comuns ⚠️
- 'dotnet' não encontrado: Reinicie o computador após instalar o SDK.
- Erro de Certificado HTTPS: Na primeira execução, rode
dotnet dev-certs https --trustpara confiar no certificado local. - OmniSharp Error: Se o VS Code reclamar, verifique se instalou o C# Dev Kit e se o SDK é compatível.
Setup 06: Python 🐍
1. Interpretador Python
- Baixe a versão mais recente em python.org.
- IMPORTANTE: Marque a caixa "Add Python to PATH" na instalação!
- Teste:
python --versionoupy --version.
2. PyCharm Community
A IDE mais poderosa para Python. 1. Baixe em jetbrains.com/pycharm.
3. VS Code + Python
- Instale a extensão "Python" da Microsoft.
- Instale a extensão "Jupyter" se quiser usar Notebooks.
4. Solução de Problemas Comuns ⚠️
- 'python' não encontrado: É o erro mais comum. Reinstale e marque a caixa "Add Python to PATH".
- Comando 'python' abre a Microsoft Store: Vá nas configurações do Windows ("Gerenciar Aliases de Execução de Aplicativo") e DESATIVE os itens do "Instalador de Aplicativo" para Python.
- Pip não funciona: Tente
python -m pip install pacote.
Setup 07: Sistemas (Rust e Go) ⚙️
Rust 🦀
O Rust usa o gerenciador rustup.
1. Acesse rustup.rs.
2. Baixe e execute o rustup-init.
3. Aceite o padrão (opção 1).
4. Reinicie o terminal e teste: cargo --version.
5. VS Code: Instale a extensão "rust-analyzer".
Go (Golang) 🐹
- Baixe em go.dev.
- Instale (Next, Next, Finish).
- Teste:
go version. - VS Code: Instale a extensão "Go" oficial.
4. Solução de Problemas Comuns ⚠️
- 'cargo' não encontrado: Reinicie o terminal. Se não funcionar, adicione
~/.cargo/bin(Linux/Mac) ou%USERPROFILE%\.cargo\bin(Windows) ao PATH. - Go Path: Certifique-se de que a variável
GOPATHestá configurada corretamente (geralmenteC:\Users\SeuUsuario\go). - Erro de Linker (Rust): No Windows, pode faltar as ferramentas de build do C++. Baixe o "Build Tools for Visual Studio".
Setup 08: Mobile (Flutter e Kotlin) 📱
Desenvolvimento mobile exige ferramentas mais pesadas.
1. Android Studio
Essencial para emular celulares Android e programar em Kotlin/Java nativo. 1. Baixe em developer.android.com/studio. 2. Instale e deixe ele baixar o Android SDK.
2. Flutter SDK
Para desenvolvimento Dart multiplataforma.
1. Baixe o SDK em flutter.dev.
2. Extraia para C:\src\flutter (exemplo).
3. Adicione C:\src\flutter\bin ao Path do Windows.
4. Rode flutter doctor no terminal para verificar o que falta.
3. VS Code
O editor preferido para Flutter. 1. Instale a extensão "Flutter" (ela instala a do Dart automaticamente).
4. Solução de Problemas Comuns ⚠️
- flutter doctor com erros: É normal. Siga o que ele diz. Geralmente é aceitar licenças (
flutter doctor --android-licenses). - Emulador não abre (HAXM/Hyper-V): Seu processador precisa ter virtualização ativada na BIOS.
- Gradle demorando: A primeira vez demora MUITO (baixa a internet inteira). Tenha paciência.
Setup 09: PHP e Servidor Local 🐘
Como o PHP roda no servidor, precisamos simular um servidor no nosso computador.
1. XAMPP (Tudo em Um)
O pacote mais fácil. Inclui Apache (Servidor), MySQL (Banco) e PHP.
1. Baixe em apachefriends.org.
2. Instale e abra o XAMPP Control Panel.
3. Clique em Start no Apache e MySQL.
4. Seus arquivos devem ficar na pasta C:\xampp\htdocs.
2. Composer (Gerenciador de Pacotes)
Essencial para usar bibliotecas modernas e frameworks como Laravel. 1. Baixe em getcomposer.org. 2. Instale. Ele deve encontrar seu PHP automaticamente.
3. Laravel (Opcional)
Para criar projetos profissionais:
4. Solução de Problemas Comuns ⚠️
- Apache não inicia (Port 80 busy): Skype ou IIS podem estar usando a porta 80. No XAMPP, vá em Config -> httpd.conf e mude
Listen 80paraListen 8080. - MySQL não conecta: Verifique se o serviço está verde no XAMPP.
- Erro de DLL: Pode faltar o "Visual C++ Redistributable" no seu Windows. Atualize-o.
Sobre
Sobre o Curso
🎓 Programação de Sistemas com Rust
Este curso foi projetado para capacitar desenvolvedores na criação de sistemas de alto desempenho e extrema confiabilidade, utilizando a linguagem Rust para unir a performance do C++ com a segurança das linguagens modernas.
🎯 Objetivos do Curso
-
Segurança Garantida --- Dominar o sistema de Ownership para eliminar bugs de memória e garantir que seu código seja seguro por construção.
-
:material-cpu: Performance Nativa --- Escreva algoritmos de alta eficiência, aproveitando o poder do hardware sem as abstrações pesadas de um Garbage Collector.
-
:material-sync-lock: Concorrência Segura --- Implementar multithreading sem medo de Race Conditions, utilizando as garantias estáticas do compilador Rust.
-
Arquitetura de Sistemas --- Aprender a organizar projetos complexos, desde ferramentas de baixo nível até serviços Web modernos e escaláveis.
📚 O Que Você Vai Aprender
Módulo 1 – Introdução e Fundamentos
- História do Rust e Configuração do Ambiente
- Variáveis, Mutabilidade e Tipos de Dados
- Controle de Fluxo (if, match e loops)
- Funções, Módulos e Organização de Código
Módulo 2 – Gerenciamento de Memória
- O Sistema de Ownership e Stack vs Heap
- Borrowing, Referências e o Borrow Checker
- Manipulação de Strings e Coleções Dinâmicas
- Modelagem de Dados com Structs e Enums
Módulo 3 – Abstrações e Qualidade
- Tratamento de Erros Profissional (Result e panic!)
- Programação Genérica e o Poder das Traits
- Closures e Iteradores de Custo Zero
- Testes Unitários, de Integração e Documentação
Módulo 4 – Especialização e Aplicações
- Concorrência Segura (Threads e Canais)
- Desenvolvimento de Ferramentas CLI com Clap
- Servidores Web de Alta Performance com Actix
- Tendências: WebAssembly e Rust no Kernel
🛠️ Metodologia
Foco 100% prático e orientado a desafios. Cada aula conta com exercícios de níveis variados e um mini-projeto aplicado, garantindo que você construa um portfólio sólido de desenvolvedor de sistemas.
Pronto para se tornar um Rustáceo? Começar Agora
Roadmap do Curso: A Jornada Rustácea 🦀
Este roadmap descreve as fases de evolução do estudante durante o curso de Rust.
🛤️ Marcos de Aprendizado
📍 Módulo 1: O Primeiro Contato
- [x] Configurar ambiente local (rustup, cargo).
- [x] Entender a sintaxe básica e tipos escalares.
- [x] Dominar o controle de fluxo com
match(O melhor amigo do Rustáceo).
🧠 Módulo 2: Pensando em Rust (O Grande Desafio)
- [x] Compreender as regras de Ownership.
- [x] Diferenciar referências mutáveis e imutáveis.
- [x] Manipular strings e coleções dinâmicas de forma segura.
🏗️ Módulo 3: Construindo Abstrações
- [x] Modelar domínios complexos com Structs e Enums.
- [x] Criar código genérico e Traits reutilizáveis.
- [x] Garantir 100% de cobertura de testes na lógica de negócio.
🚀 Módulo 4: Voando Alto
- [x] Implementar algoritmos multithread seguros.
- [x] Desenvolver uma ferramenta de terminal (CLI) profissional.
- [x] Expor funcionalidades via API Web JSON.
- [x] Concluir o Projeto Final Integrador.
"O Rust é difícil de aprender, mas é impossível de esquecer."
Materiais Complementares 📚
Bem-vindo à seção de materiais complementares do curso de Programação de Sistemas com Rust. Aqui você encontra recursos adicionais para apoiar seus estudos e aprofundar seu conhecimento técnico.
-
Slides --- Acompanhe o conteúdo teórico com slides dinâmicos e ilustrados em RevealJS.
-
Exercícios --- Pratique o Ownership, Borrowing e a lógica de sistemas com desafios semanais.
-
Quizzes --- Valide seu aprendizado com testes rápidos de 10 perguntas por módulo.
-
Projetos --- Construa desde CLIs seguras até servidores Web escaláveis para seu portfólio.
-
Ambiente --- Guias de instalação (Rustup, Cargo, VS Code e Rust Analyzer).
Versão para Impressão
Esta página foi gerada automaticamente para impressão.