Métodos

Rust permite que você associe funções aos seus novos tipos. Você faz isso com um bloco impl:

#[derive(Debug)]
struct Race {
    name: String,
    laps: Vec<i32>,
}

impl Race {
    // Sem receptor, um método estático
    fn new(name: &str) -> Self {
        Self { name: String::from(name), laps: Vec::new() }
    }

    // Empréstimo único com acesso de leitura e escrita em self
    fn add_lap(&mut self, lap: i32) {
        self.laps.push(lap);
    }

    // Empréstimo compartilhado com acesso apenas de leitura em self
    fn print_laps(&self) {
        println!("Registrou {} voltas para {}:", self.laps.len(), self.name);
        for (idx, lap) in self.laps.iter().enumerate() {
            println!("Volta {idx}: {lap} seg");
        }
    }

    // Propriedade exclusiva de self
    fn finish(self) {
        let total: i32 = self.laps.iter().sum();
        println!("Corrida {} foi encerrada, tempo total de voltas: {}", self.name, total);
    }
}

fn main() {
    let mut race = Race::new("Monaco Grand Prix");
    race.add_lap(70);
    race.add_lap(68);
    race.print_laps();
    race.add_lap(71);
    race.print_laps();
    race.finish();
    // race.add_lap(42);
}

Os argumentos self especificam o “receptor” - o objeto em que o método age. Existem vários receptores comuns para um método:

  • &self: pega emprestado o objeto do chamador como uma referência compartilhada e imutável. O objeto pode ser usado novamente depois.
  • &mut self: pega emprestado o objeto do chamador como uma referência única e mutável. O objeto pode ser usado novamente depois.
  • self: toma posse do objeto e o move do chamador. O método se torna o proprietário do objeto. O objeto será descartado (desalocado) quando o método retorna, a menos que sua ownership (posse) seja explicitamente transmitida. Posse completa não significa automaticamente mutabilidade.
  • mut self: o mesmo que acima, mas o método pode modificar o objeto.
  • Sem receptor: isso se torna um método estático (static) no struct. Normalmente usado para criar construtores que, por convenção, são chamados new.
This slide should take about 8 minutes.

Pontos Chave:

  • Pode ser útil introduzir métodos comparando-os com funções.
    • Métodos são chamados em uma instância de um tipo (como struct ou enum), o primeiro parâmetro representa a instância como self.
    • Desenvolvedores podem optar por usar métodos para aproveitar a sintaxe do receptor do método e ajudar a mantê-los mais organizados. Usando métodos, podemos manter todo o código de implementação em um local previsível.
  • Destaque o uso da palavra-chave self, um receptor de método.
    • Mostre que é um termo abreviado para self: Self e talvez mostre como o nome da struct também poderia ser usado.
    • Explique que Self é um alias de tipo para o tipo em que o bloco impl está e pode ser usado em qualquer outro lugar no bloco.
    • Observe como self é usado como outras structs e a notação de ponto pode ser usada para se referir a campos individuais.
    • Este pode ser um bom momento para demonstrar como &self difere de self modificando o código e tentando executar finish duas vezes.
    • Além das variantes de self, também existem tipos especiais de wrapper que podem ser tipos de receptores, como Box<Self>.