Setters
Fait partie de la section Programmation Orientée Objet du Journey Rust de Coddy. Leçon 12 sur 61.
Les accesseurs permettent au code externe de lire des données privées. Mais que faire si vous devez lui permettre de les modifier ? C’est là qu’interviennent les méthodes mutatrices : des méthodes publiques qui modifient les champs privés de manière contrôlée.
Un setter basique prend &mut self et une nouvelle valeur :
// wallet.rs
pub struct Wallet {
balance: f64,
}
impl Wallet {
pub fn new(initial: f64) -> Wallet {
Self { balance: initial }
}
pub fn balance(&self) -> f64 {
self.balance
}
pub fn set_balance(&mut self, amount: f64) {
self.balance = amount;
}
}
Contrairement aux getters, les setters Rust utilisent généralement le préfixe set_ pour indiquer clairement qu’ils modifient les données. Le paramètre &mut self est essentiel. Il donne à la méthode la permission de modifier les champs de la structure.
La véritable puissance des setters réside dans la validation. Au lieu d’accepter aveuglément n’importe quelle valeur, tu peux imposer des règles :
pub fn set_balance(&mut self, amount: f64) {
if amount >= 0.0 {
self.balance = amount;
}
// Les valeurs négatives sont silencieusement ignorées
}
Désormais, le portefeuille se protège lui-même : quelle que soit la valeur que le code externe tente de définir, le solde ne peut jamais devenir négatif. C’est l’encapsulation en action : la structure contrôle ses propres invariants, et le code externe ne peut tout simplement pas la placer dans un état invalide.
Défi
FacileConstruisons un système de thermostat qui montre comment les setters peuvent appliquer des règles pour maintenir les données valides. Votre thermostat aura un réglage de température qui ne pourra être ajusté que dans une plage sûre.
Vous créerez deux fichiers pour organiser votre code :
thermostat.rs: définissez une structureThermostatavec un champtemperatureprivé (i32). La structure doit être publique, mais le champ reste privé afin de la protéger contre les valeurs invalides. Implémentez :- Un constructeur
newqui prend une température initiale - Un getter
temperaturequi renvoie la température actuelle - Un setter
set_temperaturequi n'accepte que les valeurs comprises entre 10 et 30 (inclus). Si la valeur est en dehors de cette plage, la température doit rester inchangée.
- Un constructeur
main.rs: importez votre module de thermostat, créez un thermostat et montrez la validation du setter en essayant de définir différentes températures et en affichant le résultat après chaque tentative.
Le setter doit ignorer silencieusement les valeurs invalides : aucun message d'erreur, conservez simplement la température actuelle lorsqu'une tentative est faite pour la définir en dehors de la plage valide.
Votre sortie doit respecter exactement le format suivant :
Initial: {temperature}
After setting to {attempted_value}: {temperature}
After setting to {attempted_value}: {temperature}Par exemple, si vous créez un thermostat à 20, puis essayez de le régler sur 25 (valide), puis sur 50 (invalide), la sortie sera :
Initial: 20
After setting to 25: 25
After setting to 50: 25Vous recevrez trois entrées : la température initiale, la première température à essayer et la deuxième température à essayer.
Essayez vous-même
mod thermostat;
use thermostat::Thermostat;
fn main() {
// Lire les entrées
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let initial_temp: i32 = input1.trim().parse().expect("Invalid number");
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let first_attempt: i32 = input2.trim().parse().expect("Invalid number");
let mut input3 = String::new();
std::io::stdin().read_line(&mut input3).expect("Failed to read line");
let second_attempt: i32 = input3.trim().parse().expect("Invalid number");
// TODO: Créer un thermostat avec la température initiale
// TODO: Afficher la température initiale
// Format : "Initial: {temperature}"
// TODO: Tenter de définir la première température et afficher le résultat
// Format: "After setting to {attempted_value}: {temperature}"
// TODO: Tenter de définir la deuxième température et afficher le résultat
// Format: "After setting to {attempted_value}: {temperature}"
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Méthodes et comportement
Introduction aux blocs d'implémentationLe paramètre SelfMéthodes mutablesFonctions associéesBlocs d'implémentation multiplesChaînage de méthodesRécapitulatif - Actions sur le rectangle4Projet : Animal virtuel
Définir l'animalNourrir l'animal7Traits standards
Le trait DebugLe trait DisplayClone et CopyLes traits d'égalitéRécapitulatif - Point affichable10Projet : Système de documents
Le trait DrawComposant texte2Encapsulation et modules
Bases des modulesLe mot-clé publicChamps privésGettersSettersRécapitulatif - Casier sécurisé5Généricité
Structures génériquesMéthodes génériquesPlusieurs types génériquesFonctions génériquesRécapitulatif - Point de coordonnées8Les Traits comme contraintes
Syntaxe des contraintes de traitContraintes multiplesLa clause whereRetourner des types avec des traitsRécapitulatif - Afficheur générique11Design Patterns en Rust
Le pattern NewtypeCompositionLe trait DropFrom et IntoRécapitulatif - Mock de Smart Pointer3Enums avancées
Enums avec donnéesMéthodes sur les EnumsMatching des variantes de donnéesL'Enum Option revisitéeRécapitulatif - Enum Shape6Définition des Traits
Qu'est-ce qu'un Trait ?Implémenter des TraitsImplémentations par défautRedéfinir les comportements par défautTraits avec paramètresRécapitulatif - Lecteur multimédiaEntraînez-vous par vous-même : Compilateur Rust en ligne