Conceitos de Lifetimes na Programação Rust

Beginner

This tutorial is from open-source community. Access the source code

Introdução

Neste laboratório, exploraremos o conceito de lifetimes em Rust e como eles são usados pelo compilador para garantir a validade de empréstimos (borrows) no código. Lifetimes são uma construção do compilador que determinam a duração de uma variável, desde sua criação até sua destruição. Embora lifetimes e escopos estejam relacionados, eles não são a mesma coisa. Ao emprestar uma variável usando o operador &, o empréstimo tem um lifetime determinado por sua declaração, e é válido enquanto durar antes da destruição do emprestador. No entanto, o escopo do empréstimo é determinado por onde a referência é usada. O código de exemplo fornecido demonstra como lifetimes e escopos são usados na prática, com cada variável tendo seu próprio lifetime e escopo.

Nota: Se o laboratório não especificar um nome de arquivo, você pode usar qualquer nome de arquivo que desejar. Por exemplo, você pode usar main.rs, compilar e executar com rustc main.rs && ./main.

Lifetimes

Um lifetime é uma construção do compilador (ou mais especificamente, seu verificador de empréstimos) usada para garantir que todos os empréstimos sejam válidos. Especificamente, o lifetime de uma variável começa quando ela é criada e termina quando ela é destruída. Embora lifetimes e escopos sejam frequentemente referenciados juntos, eles não são a mesma coisa.

Considere, por exemplo, o caso em que emprestamos uma variável via &. O empréstimo tem um lifetime determinado por onde ele é declarado. Como resultado, o empréstimo é válido enquanto durar antes da destruição do emprestador. No entanto, o escopo do empréstimo é determinado por onde a referência é usada.

Nos exemplos a seguir e no restante desta seção, veremos como lifetimes se relacionam com escopos, bem como como os dois diferem.

// Lifetimes são anotados abaixo com linhas que denotam a criação
// e destruição de cada variável.
// `i` tem o lifetime mais longo porque seu escopo envolve completamente
// tanto `borrow1` quanto `borrow2`. A duração de `borrow1` em comparação
// com `borrow2` é irrelevante, pois são disjuntos.
fn main() {
    let i = 3; // Lifetime para `i` começa. ────────────────┐
    //                                                     │
    { //                                                   │
        let borrow1 = &i; // `borrow1` lifetime começa. ──┐│
        //                                                ││
        println!("borrow1: {}", borrow1); //              ││
    } // `borrow1` termina. ─────────────────────────────────┘│
    //                                                     │
    //                                                     │
    { //                                                   │
        let borrow2 = &i; // `borrow2` lifetime começa. ──┐│
        //                                                ││
        println!("borrow2: {}", borrow2); //              ││
    } // `borrow2` termina. ─────────────────────────────────┘│
    //                                                     │
}   // Lifetime termina. ─────────────────────────────────────┘

Note que nenhum nome ou tipo é atribuído para rotular lifetimes. Isso restringe como os lifetimes serão capazes de ser usados, como veremos.

Resumo

Parabéns! Você concluiu o laboratório de Lifetimes. Você pode praticar mais laboratórios no LabEx para aprimorar suas habilidades.