Desafio Rust
Retornando referência de struct com elisão
Enunciado
Implemente uma struct Texto<'a> que guarda conteudo: &'a str. Adicione um método palavra_mais_longa(&self) -> &str que retorna a palavra mais longa do conteúdo (separada por espaços). Use elisão de lifetimes no retorno. No main, crie uma instância com uma frase e imprima a palavra mais longa.
Requisitos
- A struct deve ter lifetime
'ae o método deve retornar&strusando elisão (sem anotar'ano retorno). - O método deve encontrar a palavra mais longa; em empate, retorne a primeira.
- O
maindeve imprimir a palavra encontrada.
Código inicial
struct Texto<'a> {
conteudo: &'a str,
}
impl<'a> Texto<'a> {
fn palavra_mais_longa(&self) -> &str {
// implemente
}
}
fn main() {
// crie e imprima
}
Saída esperada
Palavra mais longa: programação
Ver dica
Use self.conteudo.split_whitespace() e max_by_key(|p| p.len()). O retorno de max_by_key é Option<&str>; trate com unwrap_or("").
Mostrar solução
// Struct com referência e método que usa elisão de lifetimes.
struct Texto<'a> {
conteudo: &'a str,
}
impl<'a> Texto<'a> {
// O retorno &str tem lifetime ligado a &self por elisão.
fn palavra_mais_longa(&self) -> &str {
self.conteudo
.split_whitespace()
.max_by_key(|p| p.len())
.unwrap_or("")
}
}
fn main() {
let t = Texto { conteudo: "rust é uma linguagem de programação" };
println!("Palavra mais longa: {}", t.palavra_mais_longa());
}
Passo a passo
- Declaramos
struct Texto<'a>com um campoconteudo: &'a str. - No
impl<'a> Texto<'a>, implementamos o métodopalavra_mais_longa(&self) -> &str. - O retorno
&strnão tem anotação explícita. A elisão de lifetimes faz com que ele receba o mesmo lifetime de&self. - Usamos
self.conteudo.split_whitespace()para iterar sobre as palavras. max_by_key(|p| p.len())encontra a palavra com maior comprimento; em empate,max_by_keyretorna o último, mas como queremos o primeiro, usamos uma abordagem alternativa? Na verdade,max_by_keyretorna o último em empate. Para garantir o primeiro, podemos usarmax_bycom comparação que favorece o primeiro. Ajustamos para usarmax_by(|a, b| a.len().cmp(&b.len()).then(std::cmp::Ordering::Less))? Vamos simplificar:max_by_keyem empate retorna o último, então usamosmin_by_keycom chave negativa? Melhor usarmax_bycom comparação que mantém o primeiro. Veja a solução corrigida abaixo.
Correção
Para atender ao requisito de empate retornar a primeira palavra, usamos max_by com uma comparação que só troca se o próximo for estritamente maior:
fn palavra_mais_longa(&self) -> &str {
self.conteudo
.split_whitespace()
.max_by(|a, b| a.len().cmp(&b.len()).then(std::cmp::Ordering::Greater))
.unwrap_or("")
}
Passo a passo (continuação)
max_bycoma.len().cmp(&b.len()).then(Ordering::Greater)faz com que, em empate, o primeiro elemento seja mantido (poisGreaterindica queaé maior, entãoapermanece).- Tratamos o caso de string vazia com
unwrap_or(""). - No
main, criamosTextocom uma frase e imprimimos o resultado.
Por que funciona
A elisão de lifetimes em métodos com &self faz com que o retorno &str tenha o mesmo lifetime de &self. Isso é seguro porque o retorno é uma fatia do conteúdo da struct, que vive enquanto a struct viver. O método não precisa de anotação explícita, mas o compilador verifica a validade.
Erros comuns
- Tentar retornar
&strsem que ele esteja ligado a&self: se o método não tivesse&self, o compilador exigiria anotação. - Usar
max_by_keye esperar o primeiro em empate: ele retorna o último. É preciso usarmax_bycom comparação customizada. - Esquecer
unwrap_ore tentar desembrulharOptionsem tratar string vazia.
Outra forma de resolver
Você pode implementar manualmente um loop:
fn palavra_mais_longa(&self) -> &str {
let mut melhor = "";
for p in self.conteudo.split_whitespace() {
if p.len() > melhor.len() {
melhor = p;
}
}
melhor
}
Essa versão é mais explícita e mantém a primeira palavra em empate, sem depender de ordenação.
Saída esperada
Palavra mais longa: programação