Setters
Fait partie de la section Object Oriented Programming du Journey Rust de Coddy — leçon 12 sur 61.
Les getters permettent au code externe de lire des données privées. Mais que se passe-t-il si vous devez leur permettre de les modifier ? C'est là que les méthodes setters interviennent — des méthodes publiques qui modifient les champs privés de manière contrôlée.
Un setter de base 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 en 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 accorde à la méthode la permission de modifier les champs de la structure.
Le véritable pouvoir des setters est la validation. Au lieu d'accepter aveuglément n'importe quelle valeur, vous pouvez imposer des règles :
pub fn set_balance(&mut self, amount: f64) {
if amount >= 0.0 {
self.balance = amount;
}
// Negative values are silently ignored
}
Désormais, le portefeuille se protège lui-même : peu importe 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 mettre dans un état invalide.
Défi
FacileConstruisons un système de thermostat qui démontre comment les setters peuvent appliquer des règles pour maintenir la validité des données. Votre thermostat aura un réglage de température qui ne peut être ajusté que dans une plage de sécurité.
Vous allez créer deux fichiers pour organiser votre code :
thermostat.rs: Définissez une structureThermostatavec un champ privétemperature(i32). La structure doit être publique, mais le champ reste privé pour le protéger des 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 des 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 thermostat, créez un thermostat et démontrez la validation du setter en essayant de régler diverses températures et en affichant le résultat après chaque tentative.
Le setter doit ignorer silencieusement les valeurs invalides — aucun message d'erreur, gardez simplement la température actuelle inchangée lorsque quelqu'un essaie de la régler en dehors de la plage valide.
Votre sortie doit suivre ce format exact :
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 à 25 (valide) et ensuite à 50 (invalide), la sortie serait :
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 à tenter et la deuxième température à tenter.
Aide-mémoire
Les méthodes de type setter permettent au code externe de modifier des champs privés de manière contrôlée. Elles prennent &mut self pour obtenir la permission de modifier les données de la structure.
Syntaxe de base d'un setter :
pub fn set_balance(&mut self, amount: f64) {
self.balance = amount;
}Les setters en Rust utilisent généralement le préfixe set_ pour indiquer clairement qu'ils modifient des données.
Les setters permettent la validation pour appliquer des règles et maintenir l'intégrité des données :
pub fn set_balance(&mut self, amount: f64) {
if amount >= 0.0 {
self.balance = amount;
}
// Les valeurs invalides sont ignorées silencieusement
}C'est l'encapsulation en action : la structure contrôle ses propres invariants, empêchant le code externe de la placer dans un état invalide.
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 régler la première température et afficher le résultat
// Format: "After setting to {attempted_value}: {temperature}"
// TODO: Tenter de régler 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 Object Oriented Programming
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édia