W Rust istnieją dwa główne sposoby przechowywania niezmiennych danych w trakcie wykonywania programu: const i static.
Stała (const) – to niezmienna wartość obliczana w czasie kompilacji. Musi być zawsze wyraźnie typizowana i zainicjowana wyrażeniem stałym (które może być obliczone na etapie kompilacji). Stałe nie mają ustalonego adresu w pamięci i są „wstawiane” przez kompilator w miejscach ich użycia.
const MAX_ATTEMPTS: u32 = 5;
Zmienna statyczna (static) przechowuje wartość w określonym obszarze pamięci przez cały czas wykonywania programu. Jej adres jest ustalony i może być zmienna (z użyciem static mut), ale należy do niej odnosić się ze szczególną ostrożnością z powodu możliwych wyścigów danych w scenariuszach wielowątkowych.
static APP_NAME: &str = "MyApp"; static mut COUNTER: u32 = 0;
const, gdy wartość powinna być zawsze znana w czasie kompilacji i nie potrzebujesz globalnego przechowywania.static, jeśli potrzebujesz jednego miejsca przechowywania w pamięci, do którego dostęp mają wszystkie moduły, lub jeśli wartość nie może być obliczona na etapie kompilacji.Jaka jest różnica między
constastaticw Rust? Czy zmienna statyczna może odnosić się do nie-statycznej?
Odpowiedź: Główna różnica to zakres przechowywania (lifetime): const nie zapewnia, że wartość żyje w pamięci (to podmiana wartości), a static to obiekt, który żyje przez cały czas działania programu z ustalonym adresem.
Zmienna statyczna może mieć przypisaną tylko wartość, która jest znana na etapie kompilacji:
let a = 42; // static INVALID: i32 = a; // Błąd! Tylko stałe są dozwolone.
Historia
W projekcie usługi backendowej do rozdzielania obciążenia jeden z programistów użył static mut dla wspólnego licznika wywołań z różnych wątków, nie stosując synchronizacji. Doprowadziło to do wyścigów danych i nieprzewidywalnych wyników – część wywołań po prostu się gubiła. Rozwiązanie – użyć atomowych typów z std::sync::atomic lub Mutex.
Historia
Młody programista postanowił wyodrębnić powitanie użytkownika jako stałą za pomocą const, ale próbował powiązać ją z wynikiem funkcji obliczanej w czasie inicjalizacji. Kompilator zgłosił błąd, ponieważ wartość musi być określona na etapie kompilacji. Powód – stała musi być obliczalna w czasie kompilacji, podczas gdy funkcja zwraca wartość w czasie wykonywania.
Historia
W starym projekcie zastąpiono wszystkie globalne wartości static, zapominając, że literały tekstowe z odniesieniami używają obszaru pamięci programu, a niektóre deklaracje w rzeczywistości potrzebowały tylko podmiany wartości: zwiększyło to rozmiar binarki i skomplikowało zarządzanie pamięcią. Efekt – wzrost czasu uruchamiania i wycieki przy dynamicznym ładowaniu bibliotek.