Curso gratuito de Rust: A linguagem mais amada
Configurando o Projeto e Entrada/Saída de Dados (std::io)
Aprenda sobre configurando o projeto e entrada/saída de dados (std::io)
🎮 Projeto Prático: Jogo de Adivinhação - Configurando o Projeto e Entrada/Saída de Dados (std::io)
Bem-vindos ao nosso primeiro projeto prático! 🎉 Neste módulo, vamos construir um divertido jogo de adivinhação. Começaremos com os fundamentos: configurar nosso projeto Rust e aprender a interagir com o usuário através da entrada e saída padrão.
Este é o ponto de partida para transformar o conhecimento teórico em algo real e funcional. Prepare-se para codificar! 🚀
🎯 Objetivos da Aula
Ao final desta aula, você será capaz de:
- Criar um novo projeto Rust utilizando o
cargo. - Entender a estrutura básica de um projeto Rust.
- Utilizar o módulo
std::iopara ler a entrada do usuário. - Exibir mensagens no console usando a macro
println!. - Realizar operações básicas de manipulação de
String, como remover espaços em branco. - Converter
Stringpara outros tipos numéricos, lidando com possíveis erros.
1. 🏗️ Configurando o Projeto com Cargo
O Cargo é o sistema de build e gerenciador de pacotes do Rust. Ele facilita a criação, compilação e gerenciamento de dependências dos seus projetos.
Criando um Novo Projeto
Para iniciar nosso jogo de adivinhação, vamos criar um novo projeto com o cargo.
cargo new guessing_gameEste comando cria um novo diretório chamado guessing_game com a seguinte estrutura básica:
guessing_game/
├── Cargo.toml
└── src/
└── main.rs
Cargo.toml: Este é o arquivo de manifesto do seu projeto. Ele contém metadados sobre seu projeto (nome, versão, autor) e lista suas dependências. É como opackage.jsondo Node.js ou opom.xmldo Maven.src/main.rs: Este é o arquivo fonte principal do seu projeto. É aqui que o Rust procura pelo ponto de entrada do seu programa (a funçãomain).
Executando o Projeto Inicial
Você pode compilar e executar seu projeto recém-criado com:
cd guessing_game
cargo runVocê deverá ver a saída:
Hello, world!
Isso significa que seu ambiente está configurado corretamente e seu primeiro projeto Rust está funcionando! ✨
2. 🗣️ Entrada e Saída de Dados (std::io)
A interação com o usuário é fundamental para qualquer jogo. Em Rust, o módulo std::io (Input/Output) nos fornece as ferramentas necessárias para ler a entrada do teclado e exibir mensagens na tela.
Imprimindo Mensagens com println!
Já vimos println! em ação. É uma macro (note o !) usada para imprimir texto no console.
fn main() {
println!("Adivinhe o número!"); // Imprime uma string literal
let numero = 42;
println!("O número é: {}", numero); // Imprime com um placeholder
}Lendo a Entrada do Usuário com std::io::stdin
Para ler o que o usuário digita, usamos std::io::stdin(). Vamos ver um exemplo básico:
use std::io; // Importamos o módulo `io`
fn main() {
println!("Adivinhe o número!");
println!("Por favor, digite seu palpite.");
let mut palpite = String::new(); // 1. Criamos uma String mutável e vazia
io::stdin() // 2. Obtemos um "handle" para a entrada padrão
.read_line(&mut palpite) // 3. Lemos a linha e a colocamos na String `palpite`
.expect("Falha ao ler a linha"); // 4. Lidamos com erros (explicaremos isso!)
println!("Você palpitou: {}", palpite); // 5. Imprimimos o palpite do usuário
}Vamos detalhar cada parte:
let mut palpite = String::new();:String::new()cria uma nova instância vazia do tipoString, que é uma string mutável e alocada na heap.- Usamos
mutpara indicar que a variávelpalpitepode ser alterada. Strings em Rust são UTF-8.
io::stdin():- Retorna uma instância de
std::io::Stdin, que representa o handle para a entrada padrão do terminal.
- Retorna uma instância de
.read_line(&mut palpite):- Este método lê a entrada do usuário até encontrar uma quebra de linha (Enter) e a anexa à string fornecida.
- Ele espera uma referência mutável (
&mut palpite) para que possa modificar a string. - Importante:
read_lineretorna umResult, que é um tipo enumerado que representa sucesso (Ok) ou falha (Err).
.expect("Falha ao ler a linha"):Resulté um tipo fundamental em Rust para tratamento de erros. Ele tem duas variantes:Ok(T)(sucesso, contendo um valorT) eErr(E)(erro, contendo um valorE).- O método
.expect()é uma maneira simples (e muitas vezes rude em produção, mas útil para exemplos) de lidar com umResult. Se oResultforErr, ele causa umpanic!(o programa trava) e imprime a mensagem fornecida. Se forOk, ele retorna o valor contido emOk. - No caso de
read_line, ele retorna o número de bytes lidos emOk.
Manipulando a Entrada: Removendo Espaços e Quebras de Linha
Quando o usuário digita "5" e pressiona Enter, a string palpite não conterá apenas "5", mas sim "5\n" (ou "5\r\n" no Windows). Precisamos remover esses caracteres de quebra de linha.
O método trim() de String é perfeito para isso:
// ... (código anterior)
io::stdin()
.read_line(&mut palpite)
.expect("Falha ao ler a linha");
let palpite = palpite.trim(); // `trim()` retorna uma nova `&str` sem espaços em branco no início/fim
println!("Você palpitou: {}", palpite);Observe que trim() retorna uma &str (slice de string), não uma String. Se você precisar de uma String novamente, pode usar .to_string().
Convertendo a Entrada para um Número
Nosso jogo de adivinhação precisará comparar o palpite do usuário (uma String) com um número secreto. Para isso, precisamos converter a String para um tipo numérico, como u32 (inteiro de 32 bits sem sinal).
O método parse() de &str pode fazer isso:
use std::io;
fn main() {
println!("Adivinhe o número!");
println!("Por favor, digite seu palpite.");
let mut palpite = String::new();
io::stdin().read_line(&mut palpite).expect("Falha ao ler a linha");
// Convertemos a String para u32
let palpite: u32 = palpite.trim().parse().expect("Por favor, digite um número!");
println!("Você palpitou: {}", palpite);
}palpite.trim().parse():parse()também retorna umResult. Se a string não puder ser convertida para o tipo especificado (por exemplo, "abc" parau32), ele retornará umErr.- O tipo
u32é inferido pelo Rust a partir da anotaçãolet palpite: u32 = ....
.expect("Por favor, digite um número!"):- Novamente, usamos
expectpara lidar com oResultretornado porparse(). Se o usuário digitar algo que não seja um número, o programa entrará em pânico com a mensagem fornecida.
- Novamente, usamos
3. 📚 Exemplo de Código Oficial (Adaptado do The Rust Book)
O trecho de código abaixo é uma adaptação do capítulo "Programming a Guessing Game" do The Rust Book, mostrando como ler a entrada do usuário e convertê-la para um número.
use std::io; // Importa o módulo `io` da biblioteca padrão
fn main() {
println!("Adivinhe o número!"); // Imprime uma mensagem de boas-vindas
println!("Por favor, insira seu palpite."); // Solicita a entrada do usuário
let mut palpite = String::new(); // Cria uma nova String mutável para armazenar o palpite
// Lê a linha de entrada do usuário e armazena em `palpite`
// `.expect()` lida com o erro caso a leitura falhe
io::stdin()
.read_line(&mut palpite)
.expect("Falha ao ler a linha");
// Converte a String `palpite` para um número inteiro de 32 bits sem sinal (`u32`)
// `.trim()` remove espaços em branco e quebras de linha
// `.parse()` tenta converter a string para o tipo numérico especificado
// `.expect()` lida com o erro caso a conversão falhe (ex: se o usuário digitar texto)
let palpite: u32 = palpite
.trim()
.parse()
.expect("Por favor, digite um número!");
// Imprime o palpite do usuário
println!("Você palpitou: {}", palpite);
}Este código é a base para a interação inicial do nosso jogo!
4. 🚀 Exercícios/Desafios
É hora de colocar a mão na massa! Siga os passos abaixo para construir a parte inicial do seu jogo de adivinhação.
Tarefas:
- Crie um novo projeto Rust chamado
guessing_gameusandocargo new. - Abra o arquivo
src/main.rs. - Modifique a função
mainpara imprimir a mensagem de boas-vindas: "Adivinhe o número!". - Adicione uma linha para solicitar ao usuário que insira seu palpite: "Por favor, digite seu palpite.".
- Declare uma variável mutável do tipo
Stringpara armazenar a entrada do usuário. - Use
std::io::stdin().read_line()para ler a entrada do usuário e armazene-a na sua variávelString. Não se esqueça de usar.expect()para lidar com possíveis erros de leitura. - Imprima a entrada do usuário de volta no console, formatando a saída para mostrar "Você palpitou: [palpite do usuário]".
- Desafio Extra: Modifique o código para que, após ler a entrada, você use
trim()eparse()para tentar converter o palpite do usuário para umu32. Use.expect()para lidar com falhas de conversão (por exemplo, se o usuário digitar texto). Imprima o número convertido.
Dicas:
- Lembre-se de importar
use std::io;no início do seu arquivo. - Use
cargo runpara testar seu código a cada etapa. - Se encontrar erros, leia as mensagens do compilador Rust cuidadosamente; elas são muito úteis!
5. 📝 Resumo e Próximos Passos
Nesta aula, você deu os primeiros passos cruciais na construção do seu jogo de adivinhação:
- Aprendemos a iniciar um projeto Rust com
cargo new. - Exploramos a estrutura básica de um projeto Rust.
- Dominamos o uso de
println!para saída de texto. - Utilizamos
std::io::stdin().read_line()para capturar a entrada do usuário. - Vimos como
trim()remove espaços em branco eparse()converte strings em números, e como.expect()nos ajuda a lidar com osResults retornados por essas operações.
No próximo capítulo, vamos adicionar a lógica central do jogo: gerar um número aleatório e comparar o palpite do usuário com esse número. Prepare-se para aprender sobre números aleatórios e estruturas de controle de fluxo! 🎲
Até lá, continue praticando e experimentando com o código!