Ler Input do Usuário em Rust

Aprenda como ler input do usuário em Rust com stdin().read_line(), trim, parse e loops de validação. Exemplos completos e práticos.

Ler Input do Usuário em Rust

Ler dados digitados pelo usuário no terminal é uma necessidade básica de programas interativos. Rust usa std::io::stdin() para capturar entrada do teclado, com tratamento seguro de erros.

Leitura básica com stdin().read_line()

A forma fundamental de ler uma linha do teclado:

use std::io;

fn main() {
    println!("Qual é o seu nome?");

    let mut nome = String::new();
    io::stdin()
        .read_line(&mut nome)
        .expect("Erro ao ler entrada");

    // trim() remove o \n do final
    let nome = nome.trim();

    println!("Olá, {}! Bem-vindo ao Rust.", nome);
}

Interação:

Qual é o seu nome?
Maria
Olá, Maria! Bem-vindo ao Rust.

Ler e converter para número

Combine read_line() com parse() para ler números:

use std::io;

fn ler_linha() -> String {
    let mut entrada = String::new();
    io::stdin()
        .read_line(&mut entrada)
        .expect("Erro ao ler entrada");
    entrada.trim().to_string()
}

fn main() {
    println!("Digite sua idade:");
    let idade: u32 = ler_linha()
        .parse()
        .expect("Por favor, digite um número válido");

    println!("Digite sua altura em metros (ex: 1.75):");
    let altura: f64 = ler_linha()
        .parse()
        .expect("Por favor, digite um número decimal válido");

    println!("\nVocê tem {} anos e {:.2}m de altura.", idade, altura);

    let ano_nascimento = 2026 - idade;
    println!("Você nasceu por volta de {}.", ano_nascimento);
}

Interação:

Digite sua idade:
28
Digite sua altura em metros (ex: 1.75):
1.72

Você tem 28 anos e 1.72m de altura.
Você nasceu por volta de 1998.

Loop de validação (ler até input válido)

Peça novamente quando o usuário digitar algo inválido:

use std::io;
use std::io::Write;

fn ler_numero(prompt: &str, min: f64, max: f64) -> f64 {
    loop {
        print!("{}", prompt);
        io::stdout().flush().unwrap(); // garantir que o prompt aparece

        let mut entrada = String::new();
        io::stdin().read_line(&mut entrada).unwrap();

        match entrada.trim().parse::<f64>() {
            Ok(n) if n >= min && n <= max => return n,
            Ok(n) => {
                println!("Valor {:.2} fora do intervalo ({:.0} a {:.0}). Tente novamente.", n, min, max);
            }
            Err(_) => {
                println!("'{}' não é um número válido. Tente novamente.", entrada.trim());
            }
        }
    }
}

fn ler_opcao(prompt: &str, opcoes: &[&str]) -> String {
    loop {
        print!("{} [{}]: ", prompt, opcoes.join("/"));
        io::stdout().flush().unwrap();

        let mut entrada = String::new();
        io::stdin().read_line(&mut entrada).unwrap();
        let entrada = entrada.trim().to_lowercase();

        if opcoes.contains(&entrada.as_str()) {
            return entrada;
        }
        println!("Opção inválida. Escolha entre: {}", opcoes.join(", "));
    }
}

fn main() {
    println!("=== Calculadora de IMC ===\n");

    let peso = ler_numero("Peso (kg): ", 20.0, 300.0);
    let altura = ler_numero("Altura (m): ", 0.5, 2.5);

    let imc = peso / (altura * altura);

    let classificacao = match imc {
        x if x < 18.5 => "Abaixo do peso",
        x if x < 25.0 => "Peso normal",
        x if x < 30.0 => "Sobrepeso",
        _ => "Obesidade",
    };

    println!("\nResultado:");
    println!("  IMC: {:.1}", imc);
    println!("  Classificação: {}", classificacao);

    let continuar = ler_opcao("\nDeseja calcular novamente?", &["sim", "nao"]);
    if continuar == "sim" {
        println!("(Reinicie o programa para calcular novamente)");
    } else {
        println!("Até mais!");
    }
}

Interação:

=== Calculadora de IMC ===

Peso (kg): abc
'abc' não é um número válido. Tente novamente.
Peso (kg): 75
Altura (m): 1.75

Resultado:
  IMC: 24.5
  Classificação: Peso normal

Deseja calcular novamente? [sim/nao]: sim
(Reinicie o programa para calcular novamente)

Crie um menu que aceita comandos do usuário:

use std::io;
use std::io::Write;

struct ListaTarefas {
    tarefas: Vec<(String, bool)>,
}

impl ListaTarefas {
    fn new() -> Self {
        ListaTarefas { tarefas: Vec::new() }
    }

    fn adicionar(&mut self, tarefa: String) {
        self.tarefas.push((tarefa, false));
        println!("Tarefa adicionada! Total: {}", self.tarefas.len());
    }

    fn listar(&self) {
        if self.tarefas.is_empty() {
            println!("Nenhuma tarefa cadastrada.");
            return;
        }
        println!("\n--- Tarefas ---");
        for (i, (tarefa, concluida)) in self.tarefas.iter().enumerate() {
            let status = if *concluida { "[x]" } else { "[ ]" };
            println!("{} {}. {}", status, i + 1, tarefa);
        }
        println!();
    }

    fn concluir(&mut self, indice: usize) {
        if indice > 0 && indice <= self.tarefas.len() {
            self.tarefas[indice - 1].1 = true;
            println!("Tarefa '{}' concluída!", self.tarefas[indice - 1].0);
        } else {
            println!("Índice inválido!");
        }
    }
}

fn ler_comando() -> String {
    print!("> ");
    io::stdout().flush().unwrap();
    let mut entrada = String::new();
    io::stdin().read_line(&mut entrada).unwrap();
    entrada.trim().to_string()
}

fn main() {
    let mut lista = ListaTarefas::new();

    println!("=== Gerenciador de Tarefas ===");
    println!("Comandos: add <tarefa>, list, done <num>, quit\n");

    loop {
        let entrada = ler_comando();
        let partes: Vec<&str> = entrada.splitn(2, ' ').collect();

        match partes[0] {
            "add" | "a" => {
                if partes.len() > 1 {
                    lista.adicionar(partes[1].to_string());
                } else {
                    println!("Uso: add <descrição da tarefa>");
                }
            }
            "list" | "l" => lista.listar(),
            "done" | "d" => {
                if let Some(num) = partes.get(1).and_then(|s| s.parse::<usize>().ok()) {
                    lista.concluir(num);
                } else {
                    println!("Uso: done <número>");
                }
            }
            "quit" | "q" => {
                println!("Até mais!");
                break;
            }
            "" => continue,
            _ => println!("Comando desconhecido: '{}'. Use: add, list, done, quit", partes[0]),
        }
    }
}

Interação:

=== Gerenciador de Tarefas ===
Comandos: add <tarefa>, list, done <num>, quit

> add Aprender Rust
Tarefa adicionada! Total: 1
> add Criar projeto CLI
Tarefa adicionada! Total: 2
> list

--- Tarefas ---
[ ] 1. Aprender Rust
[ ] 2. Criar projeto CLI

> done 1
Tarefa 'Aprender Rust' concluída!
> list

--- Tarefas ---
[x] 1. Aprender Rust
[ ] 2. Criar projeto CLI

> quit
Até mais!

Ler senha (sem exibir no terminal)

Para ler senhas, use a crate rpassword:

Cargo.toml:

[dependencies]
rpassword = "7"
use std::io;
use std::io::Write;

fn main() {
    print!("Usuário: ");
    io::stdout().flush().unwrap();
    let mut usuario = String::new();
    io::stdin().read_line(&mut usuario).unwrap();
    let usuario = usuario.trim();

    let senha = rpassword::prompt_password("Senha: ").unwrap();

    // Validar (exemplo simples)
    if usuario == "admin" && senha == "rust123" {
        println!("Login realizado com sucesso!");
    } else {
        println!("Usuário ou senha incorretos.");
    }
}

Interação:

Usuário: admin
Senha:
Login realizado com sucesso!

Veja também