Da trilha de Rust Este conceito ainda não saiu como card do dia. ir para o card de hoje

Rust Memória Intermediário

Lifetimes

Em Rust, lifetimes são uma forma de o compilador garantir que referências não durem mais que os dados que elas apontam. Eles não mudam o tempo de vida real das variáveis; servem para anotar e verificar relacionamentos entre referências. A sintaxe usa apóstrofo ('a) e aparece em funções, structs e métodos.

O compilador aplica elisão de lifetimes em casos comuns, como funções com um único parâmetro de referência ou métodos com &self. Quando há ambiguidade, precisamos anotar explicitamente. Em structs que guardam referências, é obrigatório declarar um parâmetro de lifetime, como struct Fatia<'a> { dados: &'a str }.

O lifetime especial 'static indica que a referência pode viver por toda a execução do programa. É o caso de literais string (&'static str) e de dados alocados globalmente. Usar 'static em excesso pode indicar design rígido, mas é útil para constantes e configurações.

Entender lifetimes é essencial para escrever funções genéricas seguras e structs que emprestam dados sem copiar. Com a prática, você percebe que a maioria das anotações segue padrões simples e que o compilador geralmente consegue inferir o resto.

Pontos-chave

  • Lifetimes são anotações que descrevem por quanto tempo uma referência é válida.
  • A elisão permite omitir lifetimes em funções com um único parâmetro de referência ou métodos com &self.
  • Structs que armazenam referências precisam declarar um parâmetro de lifetime, como struct S<'a> { x: &'a T }.
  • 'static indica que a referência vive por toda a execução do programa.
  • O compilador usa lifetimes para impedir referências pendentes em tempo de compilação.
lifetimes.rs
// Exemplo de lifetimes em funções, structs e 'static

// Função que retorna a referência mais longa entre duas strings.
// O lifetime 'a garante que o retorno vive pelo menos tanto quanto os argumentos.
fn mais_longa<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

// Struct que guarda uma referência: precisa de lifetime explícito.
struct Trecho<'a> {
    texto: &'a str,
}

impl<'a> Trecho<'a> {
    // Método que retorna uma referência com o mesmo lifetime da struct.
    fn primeiro(&self) -> &'a str {
        &self.texto[..1]
    }
}

// Função que aceita apenas referências estáticas.
fn imprime_estatico(s: &'static str) {
    println!("Estático: {}", s);
}

fn main() {
    let a = String::from("curto");
    let b = String::from("muito mais longo");
    let resultado = mais_longa(&a, &b);
    println!("Mais longa: {}", resultado);

    let t = Trecho { texto: "exemplo" };
    println!("Primeiro caractere: {}", t.primeiro());

    imprime_estatico("literal global");
}

Exercícios

  1. 1
    Fácil

    Função com lifetime explícito

    Escreva uma função melhor<'a>(x: &'a str, y: &'a str) -> &'a str que retorna a string mais longa. Se tiverem o mesmo tamanho, retorne x. No main, chame a função com duas strings literais e imprima o resultado.

    Resolver
  2. 2
    Médio

    Struct com referência e método

    Crie uma struct Config<'a> que armazena nome: &'a str e valor: &'a str. Implemente um método resumo(&self) -> String que retorna uma String formatada como "{nome}={valor}". No main, instancie com literais e imprima o resumo.

    Resolver
  3. 3
    Desafio

    Retornando referência de struct com elisão

    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.

    Resolver

Continue estudando