0Pricing
Learn Rust Coding · Lekcja

Przenoszenie danych do wątków

Poprawnie użyje Pan/Pani domknięć move.

Przenoszenie danych do wątków to bezpłatna lekcja Learn Rust Coding na CoddyKit. To lekcja 2 z 4. 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 4 lekcji w sumie.

Domknięcia przechwytują otoczenie

Domknięcie przekazane do thread::spawn może używać zmiennych z otaczającego zakresu. Domyślnie Rust pożycza te zmienne.

Utworzony wątek może jednak działać dłużej niż funkcja, która go utworzyła, więc zwykłe pożyczenie nie jest bezpieczne. Rust odrzuca taki kod w czasie kompilacji.

Problem z pożyczaniem

Jeśli wątek pożycza zmienną lokalną, kompilator nie może udowodnić, że zmienna będzie istnieć wystarczająco długo. Wątek mógłby nadal działać po usunięciu zmiennej.

Poniższy kod się nie kompiluje, ponieważ domknięcie jedynie pożycza data.

use std::thread;

fn main() {
    let data = vec![1, 2, 3];
    // ERROR: closure may outlive `data`
    let h = thread::spawn(|| {
        println!("{:?}", data);
    });
    h.join().unwrap();
}

Słowo kluczowe move

Dodanie move przed domknięciem wymusza przejęcie przez nie własności przechwyconych zmiennych. Zmienne zostają przeniesione do wątku.

Wątek jest teraz właścicielem danych, więc są one zagwarantowanie ważne przez cały czas życia wątku.

use std::thread;

fn main() {
    let data = vec![1, 2, 3];
    let h = thread::spawn(move || {
        println!("{:?}", data);
    });
    h.join().unwrap();
}

Własność zostaje przeniesiona

Gdy wartość zostanie przeniesiona do wątku, pierwotny zakres nie może już jej używać. Własność została przeniesiona.

Próba użycia data w funkcji main po przeniesieniu spowodowałaby błąd kompilacji. Wątek jest teraz jedynym właścicielem.

use std::thread;

fn main() {
    let data = vec![1, 2, 3];
    let h = thread::spawn(move || println!("{:?}", data));
    // println!("{:?}", data); // ERROR: value moved
    h.join().unwrap();
}

Przenoszenie typów Copy

Typy implementujące Copy, takie jak liczby całkowite, są kopiowane zamiast przenoszone. Domknięcie otrzymuje własną kopię.

Dlatego po przechwyceniu liczby przez domknięcie move nadal można używać oryginału w funkcji main.

use std::thread;

fn main() {
    let n = 42;
    let h = thread::spawn(move || {
        println!("thread sees {}", n);
    });
    println!("main still sees {}", n);
    h.join().unwrap();
}

Send: bezpieczne przenoszenie

Typ można przenieść do innego wątku tylko wtedy, gdy implementuje cechę Send. Send oznacza, że bezpieczne jest przenoszenie własności między wątkami.

Większość typów automatycznie implementuje Send. Niektóre, takie jak Rc, nie implementują tej cechy, więc kompilator odrzuci próbę ich przeniesienia.

Rc nie implementuje Send

Rc to licznik referencji przeznaczony dla jednego wątku. Jego licznik nie jest chroniony przed równoczesnymi aktualizacjami, dlatego Rc nie implementuje Send.

Próba przeniesienia Rc do wątku kończy się błędem kompilacji. W następnej lekcji użyje Pan/Pani zamiast niego Arc.

use std::rc::Rc;
use std::thread;

fn main() {
    let r = Rc::new(5);
    // ERROR: `Rc<i32>` cannot be sent between threads safely
    let h = thread::spawn(move || println!("{}", r));
    h.join().unwrap();
}

Przenoszenie wielu wartości

Pojedyncze domknięcie move może przechwycić jednocześnie kilka zmiennych. Wszystkie zostaną przeniesione do wątku.

Jest to przydatne, gdy procedura robocza potrzebuje zarówno danych wejściowych, jak i etykiety.

use std::thread;

fn main() {
    let label = String::from("sum");
    let nums = vec![1, 2, 3, 4];
    let h = thread::spawn(move || {
        let total: i32 = nums.iter().sum();
        println!("{} = {}", label, total);
    });
    h.join().unwrap();
}

Klonowanie przed przeniesieniem

Jeśli zarówno wątek, jak i funkcja main potrzebują danej wartości, należy najpierw ją sklonować. Jeden klon należy przekazać do wątku, a drugi zachować.

Klonowanie kopiuje dane, więc każda strona posiada niezależną wartość.

use std::thread;

fn main() {
    let original = String::from("hello");
    let for_thread = original.clone();
    let h = thread::spawn(move || println!("thread: {}", for_thread));
    println!("main: {}", original);
    h.join().unwrap();
}

Zwracanie przeniesionych danych

Wątek będący właścicielem przeniesionych danych może je zwrócić, przekazując własność z powrotem do wątku nadrzędnego za pośrednictwem join.

Ten schemat przenosi dane do wątku, przetwarza je, a następnie przenosi wynik na zewnątrz.

use std::thread;

fn main() {
    let mut v = vec![3, 1, 2];
    let h = thread::spawn(move || {
        v.sort();
        v
    });
    let sorted = h.join().unwrap();
    println!("{:?}", sorted);
}

Dlaczego wymagane jest move

Bez move mechanizm sprawdzania pożyczeń zakłada, że domknięcie pożycza dane. Ponieważ utworzone wątki nie mają ustalonego czasu życia powiązanego z wywołującym, pożyczenia są niebezpieczne.

Słowo kluczowe move zamienia pożyczenia na przeniesienie własności, spełniając wymaganie 'static funkcji spawn.

Szybkie sprawdzenie

Sprawdź, czy rozumiesz przenoszenie danych do wątków.

Podsumowanie

Dowiedziałeś się, że domknięcia wątków muszą posiadać dane, z których korzystają, co uzyskuje się za pomocą słowa kluczowego move.

Przeniesienie przekazuje własność, natomiast typy Copy są kopiowane. Cecha Send oznacza, że dany typ można bezpiecznie przenosić, a Rc nie implementuje Send.

Teraz udostępnisz dane między wątkami za pomocą Arc i Mutex.

Często zadawane pytania

Czy lekcja „Przenoszenie danych do wątków” jest bezpłatna?

Tak — pełny tekst „Przenoszenie danych do wątków” 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 4 lekcji w sumie.

Co nauczysz się w „Przenoszenie danych do wątków”?

Poprawnie użyje Pan/Pani domknięć move. Ć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 4.

Ile czasu zajmuje lekcja „Przenoszenie danych do wątków”?

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. Uruchamianie wątków
  2. Przenoszenie danych do wątków
  3. Współdzielenie za pomocą Arc i Mutex
  4. Dołączanie wątków i zbieranie wyników
← Powrót do Learn Rust Coding