To zachowanie prawidłowe, nawet jeśli jest nieco niefortunne.
W pierwszym przypadku mamy to:
Zauważ, że push()
, gdy wezwał Vec<Box<Quack>>
, akceptuje Box<Quack>
, a ty przechodząc Box<Duck>
. Jest OK - rustc jest w stanie zrozumieć, że chcesz przekonwertować pudełkową wartość obiektu cechy, jak tutaj:
let duck: Box<Duck> = Box::new(Duck);
let quack: Box<Quack> = duck; // automatic coercion to a trait object
W drugim przypadku mamy to:
let mut lake: Vec<Rc<RefCell<Box<Quack>>>> = Vec::new();
let mallard: Rc<RefCell<Box<Duck>>> = Rc::new(RefCell::new(Box::new(Duck)));
lake.push(mallard);
Tutaj push()
akceptuje Rc<RefCell<Box<Quack>>>
gdy podasz Rc<RefCell<Box<Duck>>>
:
let mallard: Rc<RefCell<Box<Duck>>> = Rc::new(RefCell::new(Box::new(Duck)));
let quack: Rc<RefCell<Box<Quack>>> = mallard;
A teraz jest kłopot. Box<T>
jest typem kompatybilnym z DST, więc może być używany jako kontener dla obiektu cechy. To samo będzie wkrótce prawdziwe dla Rc
i innych inteligentnych wskaźników, gdy zaimplementowane zostanie this RFC. Jednak w tym przypadku nie ma przymusu od konkretnego typu do obiektu cechy, ponieważ Box<Duck>
znajduje się wewnątrz dodatkowych warstw typów (Rc<RefCell<..>>
).
Pamiętaj, że obiekt cech jest grubym wskaźnikiem, więc Box<Duck>
różni się od rozmiaru. W związku z tym, w zasadzie, nie są one bezpośrednio kompatybilne: nie można po prostu wziąć bajtów z Box<Duck>
i zapisać ich tam, gdzie oczekiwany jest Box<Quack>
. Rust wykonuje specjalną konwersję, tzn. Uzyskuje wskaźnik do wirtualnej tabeli dla Duck
, tworzy gruby wskaźnik i zapisuje go do zmiennej o zmiennej Box<Quack>
.
Kiedy masz Rc<RefCell<Box<Duck>>>
jednak rustc musiałby wiedzieć, jak skonstruować i destructure zarówno RefCell
i Rc
aby zastosować ten sam wskaźnik konwersji tłuszczu do swoich wewnętrznych. Naturalnie, ponieważ są to typy bibliotek, nie mogą wiedzieć, jak to zrobić. Dotyczy to również każdego innego typu opakowania, np. Arc
lub Mutex
lub nawet Vec
. Nie spodziewasz się, że będzie można użyć Vec<Box<Duck>>
jako Vec<Box<Quack>>
, prawda?
Nie ma też fakt, że w tym przykładzie z Rc
RCS stworzony z Box<Duck>
i Box<Quack>
nie zostałyby połączone - to oni mieli różne liczniki odniesienia.
Oznacza to, że konwersja z konkretnego typu do obiektu cechy może nastąpić tylko wtedy, gdy masz bezpośredni dostęp do inteligentnego wskaźnika, który obsługuje DST, a nie, gdy jest ukryty w innej strukturze.
To powiedziawszy, widzę, jak to może być możliwe, aby umożliwić to dla kilku wybranych typów. Na przykład, możemy wprowadzić pewne cechy, które są znane kompilatorowi i które mogłyby wykorzystać do "dotarcia" wewnątrz stosu owijki i przeprowadzenia wewnątrz nich konwersji cech charakterystycznych. Jednak nikt nie zaprojektował tej rzeczy i dostarczył jej jeszcze RFC - prawdopodobnie dlatego, że nie jest to funkcja bardzo potrzebna.
Uwaga: 'RefCell' jest tutaj zbędny, mogę odtworzyć problem z' Rc> '. –
Matthieu, masz rację. "RefCell" nie jest konieczne, aby wystąpił błąd. Na podstawie odpowiedzi Vladimira poniżej, widzę, dlaczego ten sam błąd występuje z lub bez 'RefCell'. – rlkw1024