Desafio Rust
Referências pendentes e escopo
Enunciado
Escreva um programa que demonstre (e depois corrija) uma tentativa de criar uma referência pendente. Crie uma função criar_referencia_invalida que tenta retornar uma referência para uma variável local. O código não deve compilar; comente-o e mostre a versão corrigida que retorna uma String própria. Explique no código com comentários o que o compilador acusaria.
Requisitos
- O código deve conter uma função que tenta retornar
&Stringde uma variável local (comentada ou em bloco#[allow(dead_code)]). - Deve haver uma versão corrigida que retorna
String(não referência). - O
maindeve chamar a versão corrigida e imprimir o resultado. - Comentários devem explicar por que a versão original não compila.
Código inicial
// Tente criar uma função que retorna &String de uma variável local
// e depois corrija retornando String.
fn main() {
// chame a versão corrigida
}
Saída esperada
Valor corrigido: Rust
Ver dica
Uma referência não pode viver mais que o valor que ela aponta. Se a variável é local, ela é destruída ao final da função, então a referência ficaria pendente.
Mostrar solução
// Esta função NÃO compila: tenta retornar uma referência para uma variável local.
// O compilador acusaria: `missing lifetime specifier` ou
// `returns a value referencing data owned by the current function`.
// fn criar_referencia_invalida() -> &String {
// let s = String::from("Rust");
// &s // s é destruída no final da função; a referência ficaria pendente
// }
// Versão corrigida: retorna uma String própria (move o valor para o chamador).
fn criar_string_valida() -> String {
let s = String::from("Rust");
s // move a String para quem chamou
}
fn main() {
let valor = criar_string_valida();
println!("Valor corrigido: {}", valor);
}
Passo a passo
- A função
criar_referencia_invalida(comentada) tenta retornar&Stringde uma variável locals. - O compilador do Rust detecta que
sé destruída ao final da função, então a referência ficaria apontando para memória inválida — uma dangling reference. - O erro típico é: missing lifetime specifier ou returns a value referencing data owned by the current function.
- Para corrigir, a função
criar_string_validaretornaString(o tipo owned). Assim, a posse é transferida para o chamador. - No
main,let valor = criar_string_valida();recebe aStringe pode usá-la com segurança. - O comentário no código explica o motivo do erro, cumprindo o requisito de demonstrar a referência pendente.
Por que funciona
O borrow checker impede referências pendentes ao garantir que o tempo de vida de uma referência não ultrapasse o tempo de vida do valor referenciado. Ao retornar uma String própria, transferimos a posse, e o valor vive no escopo do chamador, sem dependência de variáveis locais.
Erros comuns
- Retornar
&Stringde variável local: o compilador acusa missing lifetime specifier ou returns a value referencing data owned by the current function. A correção é retornarString. - Tentar usar a referência após o dono sair de escopo:
A solução é garantir que o dono viva tanto quanto a referência.let r; { let s = String::from("x"); r = &s; } println!("{}", r); // erro: `s` does not live long enough - Criar múltiplos empréstimos mutáveis:
let r1 = &mut s; let r2 = &mut s;causa erro cannot borrowsas mutable more than once at a time.
Outra forma de resolver
Usar String::from diretamente no retorno, sem variável local:
fn criar_string_valida() -> String {
String::from("Rust")
}
Saída esperada
Valor corrigido: Rust