Settery
Część sekcji Programowanie obiektowe ścieżki Rust w Coddy. Lekcja 12 z 61.
Gettery pozwalają kodowi zewnętrznemu odczytywać prywatne dane. A co, jeśli chcesz pozwolić mu je zmieniać? Właśnie do tego służą metody setter: publiczne metody, które w kontrolowany sposób modyfikują prywatne pola.
Podstawowy setter przyjmuje &mut self i nową wartość:
// 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;
}
}
W przeciwieństwie do metod odczytujących, metody ustawiające w Rust zwykle używają prefiksu set_, aby jasno wskazać, że modyfikują dane. Parametr &mut self jest niezbędny. Daje metodzie możliwość zmiany pól struktury.
Prawdziwa siła setterów tkwi w walidacji. Zamiast bezkrytycznie akceptować dowolną wartość, możesz egzekwować reguły:
pub fn set_balance(&mut self, amount: f64) {
if amount >= 0.0 {
self.balance = amount;
}
// Wartości ujemne są ignorowane bez powiadomienia
}
Teraz portfel chroni się sam: niezależnie od tego, jaką wartość próbuje ustawić kod zewnętrzny, saldo nigdy nie może być ujemne. Tak właśnie działa enkapsulacja: struktura kontroluje własne niezmienniki, a kod zewnętrzny po prostu nie może wprowadzić jej w nieprawidłowy stan.
Wyzwanie
ŁatwyStwórzmy system termostatu, który pokazuje, jak metody ustawiające mogą egzekwować reguły, aby zachować poprawność danych. Termostat będzie mieć ustawienie temperatury, które można zmieniać tylko w bezpiecznym zakresie.
Utworzysz dwa pliki, aby uporządkować swój kod:
thermostat.rs: Zdefiniuj strukturęThermostatz prywatnym polemtemperature(i32). Struktura powinna być publiczna, ale pole pozostaje prywatne, aby chronić je przed nieprawidłowymi wartościami. Zaimplementuj:- Konstruktor
new, który przyjmuje początkową temperaturę - Metodę pobierającą
temperature, która zwraca bieżącą temperaturę - Metodę ustawiającą
set_temperature, która akceptuje tylko wartości od 10 do 30 (włącznie). Jeśli wartość jest poza tym zakresem, temperatura powinna pozostać bez zmian.
- Konstruktor
main.rs: Dołącz moduł termostatu, utwórz termostat i pokaż walidację metody ustawiającej, próbując ustawić różne temperatury i wyświetlając wynik po każdej próbie.
Metoda ustawiająca powinna po cichu ignorować nieprawidłowe wartości: bez komunikatów o błędach, po prostu pozostaw bieżącą temperaturę bez zmian, gdy ktoś spróbuje ustawić wartość spoza prawidłowego zakresu.
Wynik powinien mieć dokładnie taki format:
Initial: {temperature}
After setting to {attempted_value}: {temperature}
After setting to {attempted_value}: {temperature}Na przykład, jeśli utworzysz termostat z temperaturą 20, a następnie spróbujesz ustawić ją na 25 (prawidłowa wartość), a potem na 50 (nieprawidłowa wartość), wynikiem będzie:
Initial: 20
After setting to 25: 25
After setting to 50: 25Otrzymasz trzy dane wejściowe: początkową temperaturę, pierwszą temperaturę do ustawienia i drugą temperaturę do ustawienia.
Spróbuj swoich sił
mod thermostat;
use thermostat::Thermostat;
fn main() {
// Wczytaj dane wejściowe
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: Utwórz termostat z temperaturą początkową
// TODO: Wyświetl temperaturę początkową
// Format: "Initial: {temperature}"
// TODO: Spróbuj ustawić pierwszą temperaturę i wyświetl wynik
// Format: "After setting to {attempted_value}: {temperature}"
// TODO: Spróbuj ustawić drugą temperaturę i wyświetl wynik
// Format: "After setting to {attempted_value}: {temperature}"
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Metody i zachowanie
Wprowadzenie do bloków implementacjiParametr selfMetody modyfikująceFunkcje powiązaneWiele bloków implementacjiŁańcuchowe wywoływanie metodPowtórzenie — działania na prostokącie4Projekt: Wirtualne zwierzątko
Definiowanie zwierzątkaKarmienie zwierzątka7Standardowe cechy
Cecha DebugCecha DisplayClone i CopyCechy równościPowtórka – punkt do wydrukowania10Projekt: System dokumentów
Trait DrawKomponent tekstowy2Hermetyzacja i moduły
Podstawy modułówSłowo kluczowe publicPola prywatneGetterySetteryPodsumowanie — bezpieczna skrytka5Typy generyczne
Struktury generyczneMetody generyczneWiele typów generycznychFunkcje generycznePodsumowanie – punkt współrzędnych8Cechy jako ograniczenia
Składnia ograniczeń cechWiele ograniczeńKlauzula whereZwracanie typów z użyciem cechPodsumowanie — generyczna drukarka11Wzorce projektowe w Rust
Wzorzec NewtypeKompozycjaTrait DropFrom i IntoPodsumowanie — atrapowy inteligentny wskaźnik3Zaawansowane typy wyliczeniowe
Typy wyliczeniowe z danymiMetody typów wyliczeniowychDopasowywanie wariantów danychTyp wyliczeniowy Option — powtórzeniePodsumowanie — typ wyliczeniowy Shape6Definiowanie cech
Czym jest cecha?Implementowanie cechImplementacje domyślneNadpisywanie wartości domyślnychCechy z parametramiPowtórzenie — odtwarzacz multimedialnyPoćwicz samodzielnie: Kompilator Rust online