Sur une idée de @Kysofer, je reprends mon post précédent pour mettre à jour l'exemple que j'avais donné afin de l'améliorer et de le simplifier.
L'idée est de se débarrasser des méthodes 'static' de chaque structure que j'avais appelées "new" pour les remplacer par des fonctions globales (globales au niveau du module) à côté des structures et dont le nom est plus porteur de sens. (ndr. elles remplacent les constructeurs nommés de Yegor Bugayenko en prenant un petit peu de la Factory Method défendue par Joshua Bloch).
L'intérêt des d'avoir des objets concrets qui profitent tout de suite du polymorphisme d'une interface (ici "Addition") et de wrapper ces instances dans une Box<dyn T>
pour être réutilisées ailleurs, y compris dans une struct
. Cela découple totalement les liens entres les instances puisque seules les types des interfaces fuitent.
Si à cela on ajoute l'immutabilité totale et l'absence de getter/setter, alors cela commence à être du vrai FOP (Functional-Object Programming) dont la base s'appuie sur la notion d'Elegant Objects.
Je suis contente de savoir à présent allier parfaitement paradigmes fonctionnel et objet alors qu'ils m'ont toujours été présentés comme deux antagonistes.
L'étape suivante sera de compléter l'exemple pour effectuer le même calcul en multi-thread et tirer 100% de la puissance de Rust. @Kysofer, si tu as l'envie de m'aider :P
#![allow(non_snake_case)]
// Exécution
fn main() {
let additionA = AdditionFromCouple(1, 2);
println!("Couple add : [{}]", additionA.add()); // Print 3
// Ne pas oublier de wrapper Couple dans une Box
let additionB = AdditionFromTriplet(additionA, 3);
println!("Triplet add : [{}]", additionB.add()); // Print 6
}
// Traits
trait Addition {
fn add(&self) -> i32;
}
// Structures
struct Couple {
opA: i32,
opB: i32,
}
struct Triplet {
opA: Box<dyn Addition>,
opB: i32,
}
// Implémentations
impl Addition for Couple {
fn add(&self) -> i32 {
return self.opA + self.opB;
}
}
impl Addition for Triplet {
fn add(&self) -> i32 {
return (*self.opA).add() + self.opB;
}
}
// Factory Methods (Utilisées comme constructeurs)
fn AdditionFromCouple(opA: i32, opB: i32) -> Box<dyn Addition> {
return Box::new(Couple { opA: opA, opB: opB });
}
fn AdditionFromTriplet(opA: Box<dyn Addition>, opB: i32) -> Box<dyn Addition> {
return Box::new(Triplet { opA: opA, opB: opB });
}
En réalité Bash ne possède pas le concept de packages
ou de namespaces
mais il est possible de le reproduire à partir d'une convention de nommage (ce que propose ici Google).
Dans l'idée, il suffit de préfixer toutes les déclarations de fonctions par NOM_DU_PACKAGE::
et de faire la même chose pour les invocations. Par exemple avec un "Hello World!" :
# Définition
CORE::hello() {
echo "Hello ${1}!"
}
export -f CORE::hello
# Usage
CORE::hello "World"
Et ça marche. Par contre impossible de savoir si les double deux-points sont POSIX ou non.