Pular para o conteúdo principal
Módulo 3 · Lição 2 de 26/14 no curso~15 min
Lições do módulo (2/2)

Referências e empréstimos

No Rust, transferir propriedade de funções pode ser entediante. Para resolver isso, Rust usa referências (&).

A criação de uma referência a um valor é chamada de Empréstimo.

Referências imutáveis

Uma referência é declarada prefixando o tipo ou variável com o símbolo &. Por padrão, as referências são imutáveis: permitem ler o valor, mas não modificá-lo.

Rust
fn main() {
    let s1 = String::from("hello");

    // We pass a reference to s1, not ownership
    let len = calculate_length(&s1);

    // s1 is still usable here!
    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize { // s is a reference to a String
    s.len()
} // Here, s goes out of scope, but since it doesn't own the value, nothing happens

Referências mutáveis

Se precisar modificar um valor emprestado, você deverá usar uma referência mutável com &mut. A variável original também deve ser declarada mutável com mut:

Rust
fn main() {
    let mut s = String::from("hello");

    // We pass a mutable reference
    change(&mut s);

    println!("{}", s); // Prints "hello, world"
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

As regras do empréstimo

Para evitar corrupção de memória e corridas de dados em tempo de compilação, Rust impõe duas regras fundamentais:

  1. Você pode ter qualquer número de referências imutáveis (&T) para um valor ao mesmo tempo.
  2. OU você pode ter exatamente uma referência mutável (&mut T) para um valor por vez.

Você absolutamente não pode misturar referências imutáveis ​​e mutáveis ​​para o mesmo valor no mesmo escopo:

Rust
let mut s = String::from("hello");

let r1 = &s; // Valid
let r2 = &s; // Valid
// let r3 = &mut s; // COMPILATION ERROR! You cannot create &mut s if s is already borrowed as immutable

Escopo de referência e tempos de vida não lexicais (NLL)

Historicamente, o escopo de uma referência durava até o final do bloco em que foi criada. Hoje, o compilador do Rust é mais inteligente graças ao Non-Lexical Lifetimes (NLL): o escopo de uma referência termina na última linha em que é realmente usada, não necessariamente no final do bloco.

Isso torna o seguinte código perfeitamente válido:

Rust
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} and {}", r1, r2); // Last use of r1 and r2. The immutable references expire here!

let r3 = &mut s; // Valid! No active immutable references exist at this point

Experimente você mesmo

Exercício#rust.m3.l2.e1
Tentativas: 0Carregando…

Passe uma referência imutável de s1 para a função calcula_comprimento usando o símbolo &.

Carregando editor…
Mostrar dica

Substitua `/* TODO \_/`com`&s1` para passar uma referência imutável para a string.

Solução disponível após 3 tentativas

Exercício#rust.m3.l2.e2
Tentativas: 0Carregando…

Torne a variável s mutável (let mut s) e passe uma referência mutável (&mut s) para a função change para permitir que ela modifique a string.

Carregando editor…
Mostrar dica

Use `let mut s` em vez de`let s`e chame`change(&mut s);`.

Solução disponível após 3 tentativas

Exercício#rust.m3.l2.e3
Tentativas: 0Carregando…

Declare a variable s containing String::from("Rust"). Create two distinct immutable references r1 and r2 to s, and finally print both references separated by a space using the println! macro.

Carregando editor…
Mostrar dica

Assign `let r1 = &s;` and `let r2 = &s;` to obtain two immutable references, then print them with `println!("{} {}", r1, r2);`.

Solução disponível após 3 tentativas