Aktualizacja Rust 1,0
w Rust 1,0 a później kod w przykładzie (gdy uint
s zastąpiono jakimś istniejącym typu) nie powiedzie się z innego błędu:
% rustc test.rs
test.rs:23:9: 23:13 error: the trait `core::marker::Sync` is not implemented for the type `core::cell::UnsafeCell<usize>` [E0277]
test.rs:23 func(&r7)
^~~~
test.rs:23:9: 23:13 help: run `rustc --explain E0277` to see a detailed explanation
test.rs:23:9: 23:13 note: `core::cell::UnsafeCell<usize>` cannot be shared between threads safely
test.rs:23:9: 23:13 note: required because it appears within the type `core::cell::Cell<usize>`
test.rs:23:9: 23:13 note: required because it appears within the type `core::cell::BorrowRef<'_>`
test.rs:23:9: 23:13 note: required because it appears within the type `core::cell::Ref<'_, i32>`
test.rs:23:9: 23:13 note: required by `func`
To jest trochę podstępna - inna cecha, Sync
, pojawiła się znikąd.
Typ implementujący cechę Send
(choć jej dokumentacja na pewno brak jest od teraz) jest czymś, co można przenieść przez granice zadań. Większość typów to Send
, ale niektóre, takie jak Rc
i Weak
, nie są Send
, ponieważ wystąpienia takich typów mogą współdzielić niezsynchronizowany stan zmienny, a zatem nie są bezpieczne w użyciu z wielu wątków.
W starszych wersjach Rust Send
domniemana 'static
, więc referencje nie były Send
. Jednak od rdzy 1.0 Send
już nie oznacza 'static
, dlatego referencje mogą być przesyłane między wątkami. Jednakże, w celu &T
bycia Send
, T
musi być Sync
: jest to wymagane przez następujący realizacji:
impl<'a, T> Send for &'a T where T: Sync + ?Sized
Ale w naszym przypadku nie jesteśmy wymagający, że &T
jest Send
tylko wymagamy T
jest Send
, więc nie powinno to mieć znaczenia, prawda?
Nie. W rzeczywistości nadal są to odniesienia, nawet nie widzimy ich od razu. Pamiętaj, że każdy typ komponentu musi być Send
, a każdy jego element musi być Send
, tzn. Każde pole struktury i każda część każdego z wyliczonych wariantów wyliczenia musi być również Send
dla tej struktury/enum, aby być również Send
. core::cell::Ref
wewnętrznie contains instancja struct BorrowRef
, która z kolei contains odniesienie do Cell<BorrowFlag>
. I tutaj jest, skąd pochodzi Sync
: w kolejności lub &Cell<BorrowFlag>
jako Send
, Cell<BorrowFlag>
musi być Sync
; jednak nie jest i nie może być Sync
, ponieważ zapewnia niezsynchronizowaną wewnętrzną zmienność. Jest to faktyczna przyczyna błędu.
Świetna odpowiedź dzięki, rozumiem teraz! – user3762625