Historia de la pregunta
Rust toma prestada la concepción de métodos de los lenguajes orientados a objetos, pero los implementa de manera diferente: en lugar del habitual this o self, los métodos aceptan explícitamente un parámetro self. Las funciones asociadas surgieron como una alternativa a los métodos estáticos en otros lenguajes de programación: están asociadas a un tipo, pero no a un valor concreto.
Problema
A menudo se confunden los métodos, las funciones asociadas y las funciones libres. No es obvio cuándo usar un método con self y cuándo una función asociada sin self. Existen preguntas sobre visibilidad, autodereferenciación y transferencia de propiedad.
Solución
Los métodos en Rust se declaran con el primer parámetro self/ &self/ &mut self dentro de un bloque impl (normalmente para struct o enum). Se llaman en una instancia: object.method(). Las funciones asociadas (por ejemplo, new, from) se declaran también dentro de impl, pero sin el primer parámetro self y se llaman a través de dos puntos: Type::function().
Ejemplo de código:
struct Point { x: f64, y: f64, } impl Point { // Función asociada (constructor) fn new(x: f64, y: f64) -> Self { Self { x, y } } // Método: requiere self fn distance_from_origin(&self) -> f64 { (self.x.powi(2) + self.y.powi(2)).sqrt() } } let p = Point::new(3.0, 4.0); printf!("{}", p.distance_from_origin()); // 5.0
Características clave:
::¿Se pueden llamar funciones asociadas a través de una instancia (a través del punto)?
Esto es posible (por ejemplo, p.new(1.0, 2.0)), pero se desaconseja encarecidamente: esto puede causar confusión, ya que la función asociada no tiene acceso al objeto actual, y la instancia se pasa sin consideración. Es mejor usar la sintaxis Type::func().
Ejemplo de código:
let p = Point::new(1.0, 2.0); let q = p.new(0.0, 0.0); // Funciona, pero no es la mejor práctica!
¿Pueden los métodos ser asincrónicos?
Sí. Los métodos pueden declararse con la palabra clave async de la misma manera que las funciones libres:
impl Foo { async fn do_async(&self) { // ... } }
¿Se pueden declarar tanto métodos como funciones asociadas dentro de un mismo bloque impl?
Sí, cualquier combinación es válida. También es posible declarar varios bloques impl para un mismo tipo.
Un novato declaró la función new fuera de impl y trató de usarla como constructor, y luego accidentalmente llamó a través de una instancia: p.new(1.0, 2.0).
Ventajas:
Funciona rápidamente (el compilador lo permite).
Desventajas:
El código es ilegible, difícil de mantener, complicado de usar los métodos con la propiedad self correcta.
Todos los métodos y funciones asociadas se declaran estrictamente dentro de impl, se utilizan las sintaxis de llamada correctas (Type::new() para constructores, obj.method() para acciones).
Ventajas:
Alta legibilidad, conformidad con las mejores prácticas.
Desventajas:
Requiere conocimiento de las idiomaticas de Rust y atención a la sintaxis.