Panic: Index Out of Bounds
O panic “index out of bounds” ocorre quando você tenta acessar um elemento de um array, slice ou Vec usando um índice que está fora do intervalo válido. É um erro de runtime que causa o encerramento imediato do programa.
A Mensagem de Erro
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 5', src/main.rs:4:20
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Variação com slices:
thread 'main' panicked at 'range end index 10 out of range for slice of length 3', src/main.rs:4:22
O Que Significa
Arrays, slices e Vec no Rust são indexados a partir de 0. Um vetor com 3 elementos tem índices válidos 0, 1 e 2. Acessar o índice 3 (ou qualquer índice >= comprimento) causa panic.
O Rust faz bounds checking (verificação de limites) em todo acesso por índice. Isso é diferente de C/C++, onde acessar fora dos limites causa comportamento indefinido silenciosamente. No Rust, o programa aborta com uma mensagem clara em vez de continuar com dados corrompidos.
Cenários comuns:
- Loop com índice errado —
for i in 0..=len(deveria ser0..len) - Vetor vazio — acessar
vec[0]sem verificar se está vazio - Off-by-one — erro clássico de “um a mais” ou “um a menos”
- Índice calculado — resultado de cálculo que excede o comprimento
Código com Erro
fn main() {
let numeros = vec![10, 20, 30];
// PANIC: índice 3 não existe (válidos: 0, 1, 2)
println!("{}", numeros[3]);
// PANIC: vetor pode estar vazio
let vazio: Vec<i32> = Vec::new();
println!("{}", vazio[0]);
// PANIC: off-by-one no loop
for i in 0..=numeros.len() { // =numeros.len() está fora
println!("{}", numeros[i]);
}
// PANIC: slice fora dos limites
let fatia = &numeros[1..5];
}
Como Resolver
Solução 1: Usar .get() para Acesso Seguro
O método .get() retorna Option<&T> — None se o índice for inválido:
fn main() {
let numeros = vec![10, 20, 30];
// Seguro: retorna None se não existir
match numeros.get(5) {
Some(valor) => println!("Valor: {}", valor),
None => println!("Índice inválido"),
}
// Com unwrap_or para valor padrão
let valor = numeros.get(5).unwrap_or(&0);
println!("Valor: {}", valor);
// if let para caso simples
if let Some(primeiro) = numeros.get(0) {
println!("Primeiro: {}", primeiro);
}
}
Para slices, use .get(range):
fn main() {
let numeros = vec![10, 20, 30];
// Seguro: retorna None se o range for inválido
if let Some(fatia) = numeros.get(1..5) {
println!("{:?}", fatia);
} else {
println!("Range inválido");
}
}
Solução 2: Usar Iteradores em Vez de Índices
Iteradores eliminam completamente o risco de index out of bounds:
fn main() {
let numeros = vec![10, 20, 30, 40, 50];
// Em vez de for i in 0..numeros.len(), use:
for numero in &numeros {
println!("{}", numero);
}
// Com índice se necessário
for (i, numero) in numeros.iter().enumerate() {
println!("[{}] = {}", i, numero);
}
// Processar pares de elementos adjacentes
for par in numeros.windows(2) {
println!("{} -> {}", par[0], par[1]);
}
// Processar em chunks
for grupo in numeros.chunks(2) {
println!("{:?}", grupo);
}
}
Solução 3: Verificar Limites Antes de Acessar
fn main() {
let numeros = vec![10, 20, 30];
let indice = 5;
// Verificação explícita
if indice < numeros.len() {
println!("{}", numeros[indice]);
} else {
println!("Índice {} fora dos limites (max: {})", indice, numeros.len() - 1);
}
// Para primeiro/último elemento
if let Some(primeiro) = numeros.first() {
println!("Primeiro: {}", primeiro);
}
if let Some(ultimo) = numeros.last() {
println!("Último: {}", ultimo);
}
// Verificar se não está vazio
if !numeros.is_empty() {
println!("Primeiro: {}", numeros[0]);
}
}
Solução 4: Usar first(), last() e Métodos Seguros
fn main() {
let numeros = vec![10, 20, 30];
// Métodos seguros que retornam Option
let primeiro = numeros.first(); // Some(&10)
let ultimo = numeros.last(); // Some(&30)
// Para vetores mutáveis
let mut dados = vec![1, 2, 3];
if let Some(primeiro) = dados.first_mut() {
*primeiro = 100;
}
println!("{:?}", dados); // [100, 2, 3]
// pop() remove e retorna o último elemento
let removido = dados.pop(); // Some(3)
println!("Removido: {:?}", removido);
}
Solução 5: Usar saturating_sub para Evitar Underflow em Índices
fn main() {
let numeros = vec![10, 20, 30, 40, 50];
let posicao: usize = 1;
// Pegar elementos ao redor de uma posição
let inicio = posicao.saturating_sub(2); // Não vai abaixo de 0
let fim = (posicao + 3).min(numeros.len()); // Não passa do comprimento
let vizinhos = &numeros[inicio..fim];
println!("Vizinhos: {:?}", vizinhos);
}
Padrão Comum: Processar Entrada do Usuário
fn buscar_item(lista: &[String], indice_str: &str) -> Option<&String> {
let indice: usize = indice_str.parse().ok()?;
lista.get(indice)
}
fn main() {
let itens = vec![
String::from("maçã"),
String::from("banana"),
String::from("laranja"),
];
// Simula input do usuário
let entrada = "1";
match buscar_item(&itens, entrada) {
Some(item) => println!("Item: {}", item),
None => println!("Item não encontrado"),
}
}
Comparação de Abordagens
| Abordagem | Panic? | Uso recomendado |
|---|---|---|
vec[i] | Sim, se fora | Quando o índice é garantido válido |
vec.get(i) | Nao | Acesso com índice de fonte externa |
for item in &vec | Nao | Iterar sobre todos os elementos |
vec.first() / vec.last() | Nao | Acessar extremidades |
if i < vec.len() | Nao | Verificação manual |