Funções e Métodos Associados
Algumas funções são conectadas à um topo específico. Existem em duas formas: funções associadas, e métodos. As funções associadas são funções que são definidas geralmente sobre um tipo, enquanto os métodos são funções associadas que são chamados sobre uma instância específica dum tipo:
struct Point { x: f64, y: f64, } // Bloco de implementação, todas funções associadas do `Point` // e os métodos são colocados neste bloco impl Point { // Isto é uma "função associada" pois esta função está associada à // um tipo específico, que é, `Point`. // // Funções associadas não precisam ser chamadas com uma instância. // Estas funções são geralmente usadas como construtoras. fn origin() -> Point { Point { x: 0.0, y: 0.0 } } // Uma outra função associada, recebendo dois argumentos: fn new(x: f64, y: f64) -> Point { Point { x: x, y: y } } } struct Rectangle { p1: Point, p2: Point, } impl Rectangle { // Isto é um método // `&self` é açúcar sintático para `self: &Self`, // aonde `Self` é o tipo do objeto chamador. // Neste caso `Self` = `Rectangle` fn area(&self) -> f64 { // `self` dá acesso aos campos da estrutura através do // operador ponto let Point { x: x1, y: y1 } = self.p1; let Point { x: x2, y: y2 } = self.p2; // `abs` é um método de `f64` que retorna o // valor absoluto do chamador ((x1 - x2) * (y1 - y2)).abs() } fn perimeter(&self) -> f64 { let Point { x: x1, y: y1 } = self.p1; let Point { x: x2, y: y2 } = self.p2; 2.0 * ((x1 - x2).abs() + (y1 - y2).abs()) } // Este método exige que objeto chamador seja mutável. // `&mut self` é açúcar para `self: &mut Self` fn translate(&mut self, x: f64, y: f64) { self.p1.x += x; self.p2.x += x; self.p1.y += y; self.p2.y += y; } } // `Pair` possui os recursos: dois amontoados alocados de inteiros struct Pair(Box<i32>, Box<i32>); impl Pair { // Este método "consome" os recursos do objeto chamador // `self` é açúcar para `self: Self` fn destroy(self) { // Desestruturar `self` let Pair(first, second) = self; println!("Destroying Pair({}, {})", first, second); // `first` e `second` saem do âmbito e são liberados } } fn main() { let rectangle = Rectangle { // As funções associadas são chamadas usando dois-pontos duplos p1: Point::origin(), p2: Point::new(3.0, 4.0), }; // Os métodos são chamados usando o operador ponto // Nota que o primeiro argumento `&self` é implicitamente passado, isto é, // `rectangle.perimeter()` === `Rectangle::perimeter(&rectangle)` println!("Rectangle perimeter: {}", rectangle.perimeter()); println!("Rectangle area: {}", rectangle.area()); let mut square = Rectangle { p1: Point::origin(), p2: Point::new(1.0, 1.0), }; // Error! `rectangle` é imutável, mas este método exige um objeto mutável //rectangle.translate(1.0, 0.0); // TODO ^ Tente desfazer o comentário desta linha // Okay! Os objetos mutáveis podem chamar métodos mutáveis square.translate(1.0, 1.0); let pair = Pair(Box::new(1), Box::new(2)); pair.destroy(); // Error! A chama de `destroy` anterior "consumiu" `pair` //pair.destroy(); // TODO ^ Tente desfazer o comentário desta linha }