Historique de la question
Rust emprunte le concept de méthodes aux langages orientés objet, mais les implémente différemment : au lieu du traditionnel this ou self, les méthodes prennent explicitement un paramètre self. Les fonctions associées, quant à elles, sont apparues comme une alternative aux méthodes statiques dans d'autres langages de programmation — elles sont liées au type, mais pas à une valeur spécifique.
Problème
On confond souvent méthodes, fonctions associées et fonctions libres. Il n'est pas toujours évident de savoir quand utiliser une méthode avec self et quand utiliser une fonction associée sans self. Il y a des questions de visibilité, d'auto-déréférencement et de transfert de propriété.
Solution
Les méthodes en Rust sont déclarées avec le premier paramètre self / &self / &mut self à l'intérieur d'un bloc impl (généralement pour struct ou enum). Elles sont appelées sur une instance : object.method(). Les fonctions associées (par exemple, new, from) sont également déclarées à l'intérieur d'un impl, mais sans le premier paramètre self et sont appelées avec des doubles deux-points : Type::function().
Exemple de code :
struct Point { x: f64, y: f64, } impl Point { // Fonction associée (constructeur) fn new(x: f64, y: f64) -> Self { Self { x, y } } // Méthode : nécessite 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
Caractéristiques clés :
::Peut-on appeler des fonctions associées via une instance (avec un point) ?
C'est possible (par exemple, p.new(1.0, 2.0)), mais c'est fortement déconseillé : cela crée une confusion, car la fonction associée n'a pas accès à l'objet courant et l'instance est transmise sans être prise en compte. Il vaut mieux utiliser la syntaxe Type::func().
Exemple de code :
let p = Point::new(1.0, 2.0); let q = p.new(0.0, 0.0); // Ça marche, mais ce n'est pas une bonne pratique !
Les méthodes peuvent-elles être asynchrones ?
Oui. Les méthodes peuvent être déclarées avec le mot clé async tout comme les fonctions libres :
impl Foo { async fn do_async(&self) { // ... } }
Peut-on déclarer à l'intérieur d'un même bloc impl des méthodes et des fonctions associées ?
Oui — toutes les combinaisons sont possibles. Il est également possible de déclarer plusieurs blocs impl pour un même type.
Un débutant a déclaré une fonction new en dehors de l'impl et a essayé de l'utiliser comme constructeur, puis a accidentellement appelée via une instance : p.new(1.0, 2.0).
Avantages :
Fonctionne rapidement (le compilateur le permet).
Inconvénients :
Code peu lisible, difficile à maintenir, compliqué d'utiliser des méthodes avec un bon transfert de propriété pour self.
Toutes les méthodes et fonctions associées sont déclarées strictement à l'intérieur de l'impl, et les bonnes syntaxes d'appel sont utilisées (Type::new() pour les constructeurs, obj.method() pour les actions).
Avantages :
Haute lisibilité, conformité aux meilleures pratiques.
Inconvénients :
Nécessite la connaissance des idiomes Rust et de l'attention au syntaxe.