0Pricing
Learn Rust Coding · Lekcja

Wewnętrzna mutowalność: RefCell, Cell

Poznają Państwo `RefCell` i `Cell` służące do zapewniania wewnętrznej mutowalności, umożliwiającej bezpieczny mutowalny dostęp do danych przez niemutowalną referencję.

Wewnętrzna mutowalność: RefCell, Cell to bezpłatna lekcja Learn Rust Coding na CoddyKit. To lekcja 2 z 3. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Learn Rust Coding, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Learn Rust Coding zawiera 3 lekcji w sumie.

Czym jest mutowalność wewnętrzna?

W języku Rust zasady pożyczania zazwyczaj uniemożliwiają uzyskanie mutowalnego odwołania do danych, jeśli istnieje już do nich niemutowalne odwołanie. Zapewnia to bezpieczeństwo danych.

Mutowalność wewnętrzna to wzorzec projektowy pozwalający modyfikować dane nawet wtedy, gdy dostępne jest tylko niemutowalne odwołanie do nich. Można ją traktować jako kontrolowany wyjątek od zwykłych zasad języka Rust, stosowany w określonych sytuacjach.

`Cell<T>`: dla typów implementujących Copy

Typ Cell<T> zapewnia mutowalność wewnętrzną typom implementującym trait Copy (takim jak liczby całkowite, wartości logiczne i znaki). Działa poprzez zastępowanie wartości znajdującej się wewnątrz.

  • get(): zwraca kopię wartości znajdującej się w Cell.
  • set(value): zastępuje wartość w Cell nową wartością.

To proste i wydajne rozwiązanie dla małych danych, które można kopiować.

Aktualizowanie wartości za pomocą `Cell`

Oto podstawowy przykład użycia Cell. Proszę zauważyć, że możemy zmienić wartość wewnątrz Cell, mimo że sam Cell został zadeklarowany jako niemutowalny.

use std::cell::Cell;

fn main() {
  let my_num = Cell::new(10);
  println!("Initial value: {}", my_num.get());

  my_num.set(20);
  println!("Updated value: {}", my_num.get());

  let x = &my_num;
  x.set(30); // Still works via immutable reference!
  println!("Via immutable ref: {}", my_num.get());
}

`RefCell<T>`: dla typów nieimplementujących Copy

Gdy potrzebna jest mutowalność wewnętrzna dla typów, które nie implementują Copy (takich jak String, Vec lub własne struktury), używa się RefCell<T>.

RefCell pozwala uzyskiwać mutowalne odwołania do danych wewnętrznych, ale wymusza przestrzeganie zasad pożyczania języka Rust w czasie działania programu, a nie w czasie kompilacji.

Pożyczanie w czasie działania za pomocą `RefCell`

RefCell udostępnia metody zwracające inteligentne wskaźniki:

  • borrow(): Zwraca Ref (niezmienny inteligentny wskaźnik). Jednocześnie można utworzyć wiele niezmiennych pożyczeń.
  • borrow_mut(): Zwraca RefMut (zmienny inteligentny wskaźnik). Jednocześnie można utworzyć tylko jedno zmienne pożyczenie.

Naruszenie tych reguł w czasie działania programu spowoduje wywołanie panic!.

Używanie `RefCell` (niezmienne pożyczenie)

W tym przykładzie używamy borrow(), aby uzyskać niezmienne odwołanie do obiektu String znajdującego się w RefCell. Możemy wyświetlić jego zawartość.

use std::cell::RefCell;

fn main() {
  let my_string_cell = RefCell::new(String::from("Hello"));

  let s1 = my_string_cell.borrow();
  println!("Value: {}", *s1); // Dereference Ref to get String

  let s2 = my_string_cell.borrow(); // Multiple immutable borrows are fine
  println!("Another value: {}", *s2);
}

Używanie `RefCell` (zmienne pożyczenie)

Teraz uzyskajmy zmienne odwołanie za pomocą borrow_mut(). Pozwala nam to modyfikować obiekt String. Należy pamiętać, że gdy s_mut znajdzie się w zakresie, żadne inne pożyczenia — zmienne ani niezmienne — nie są dozwolone.

use std::cell::RefCell;

fn main() {
  let my_string_cell = RefCell::new(String::from("World"));

  { // Scope for the mutable borrow
    let mut s_mut = my_string_cell.borrow_mut();
    s_mut.push_str(", Rust!");
  }
  // s_mut is out of scope here, so we can borrow again

  let s_final = my_string_cell.borrow();
  println!("Final value: {}", *s_final);
}

Panika w czasie działania `RefCell`

Jeśli spróbują Państwo uzyskać zmienne pożyczenie, gdy aktywne jest inne zmienne pożyczenie (lub dowolne niezmienne pożyczenie), RefCell spowoduje wywołanie panic! w czasie działania programu. Zapobiega to uszkodzeniu danych.

Proszę uruchomić ten kod, aby zobaczyć to w praktyce. Program zakończy się błędem „borrow already in use”.

use std::cell::RefCell;

fn main() {
  let my_value = RefCell::new(vec![1, 2, 3]);

  let _first_mut_borrow = my_value.borrow_mut();
  println!("First mutable borrow is active.");

  // This line will cause a runtime panic!
  // Try commenting it out to see the program run successfully.
  let _second_mut_borrow = my_value.borrow_mut();

  println!("This line will not be reached.");
}

Podsumowanie: `Cell` a `RefCell`

Wybór między Cell a RefCell zależy od typu danych oraz sposobu, w jaki trzeba z nimi pracować:

  • Cell<T>: Należy używać w przypadku typów implementujących Copy. Zastępuje całą wartość i jest zazwyczaj prostszy oraz wydajniejszy.
  • RefCell<T>: Należy używać w przypadku typów, które nie implementują Copy. Udostępnia odwołania do danych wewnętrznych i sprawdza reguły pożyczania w czasie działania programu, umożliwiając bardziej złożone modyfikacje.

Szybkie sprawdzenie: Cell czy RefCell?

Mają Państwo struct, który musi przechowywać zmienny licznik (u32) oraz zmienną listę nazw (Vec<String>), a oba pola muszą być aktualizowane za pośrednictwem niezmiennego odwołania do struct. Jakich typów mutowalności wewnętrznej należy użyć dla poszczególnych pól?

Powtórzenie: mutowalność wewnętrzna

Poznali Państwo wzorzec mutowalności wewnętrznej w języku Rust, który pozwala w kontrolowany i bezpieczny sposób modyfikować dane za pośrednictwem niezmiennego odwołania.

  • Cell<T>: Dla typów Copy; zastępuje wartość wewnętrzną.
  • RefCell<T>: Dla typów niebędących Copy; udostępnia sprawdzane w czasie działania programu zmienne i niezmienne odwołania.
  • Naruszenie reguł RefCell prowadzi do paniki w czasie działania programu, zapewniając bezpieczeństwo.

Typy te mają kluczowe znaczenie w przypadku wzorców takich jak obiekty pozorowane, odwołania cykliczne czy sytuacje, w których współdzielone niezmienne odwołanie musi śledzić stan wewnętrzny.

Często zadawane pytania

Czy lekcja „Wewnętrzna mutowalność: RefCell, Cell” jest bezpłatna?

Tak — pełny tekst „Wewnętrzna mutowalność: RefCell, Cell” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Learn Rust Coding, przejdź na CoddyKit PRO. Kurs Learn Rust Coding zawiera 3 lekcji w sumie.

Co nauczysz się w „Wewnętrzna mutowalność: RefCell, Cell”?

Poznają Państwo `RefCell` i `Cell` służące do zapewniania wewnętrznej mutowalności, umożliwiającej bezpieczny mutowalny dostęp do danych przez niemutowalną referencję. Ćwiczysz Learn Rust Coding z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Learn Rust Coding?

Nie wymagamy żadnego doświadczenia. Learn Rust Coding w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 3.

Ile czasu zajmuje lekcja „Wewnętrzna mutowalność: RefCell, Cell”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Learn Rust Coding?

Tak. Każda lekcja Learn Rust Coding zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Inteligentne wskaźniki Box, Rc i Arc
  2. Wewnętrzna mutowalność: RefCell, Cell
  3. Beztroska współbieżność z wątkami
← Powrót do Learn Rust Coding