Đây là hành vi đúng, ngay cả khi nó có phần không may.
Trong trường hợp đầu tiên chúng tôi có điều này:
Lưu ý rằng push()
, khi kêu gọi Vec<Box<Quack>>
, chấp nhận Box<Quack>
, và bạn đang đi qua Box<Duck>
. Đây là OK - rustc có thể hiểu rằng bạn muốn chuyển đổi một giá trị đóng hộp đến một đối tượng đặc điểm, như ở đây:
let duck: Box<Duck> = Box::new(Duck);
let quack: Box<Quack> = duck; // automatic coercion to a trait object
Trong trường hợp thứ hai, chúng tôi đã này:
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);
đây push()
chấp nhận Rc<RefCell<Box<Quack>>>
khi bạn cung cấp Rc<RefCell<Box<Duck>>>
:
let mallard: Rc<RefCell<Box<Duck>>> = Rc::new(RefCell::new(Box::new(Duck)));
let quack: Rc<RefCell<Box<Quack>>> = mallard;
Và hiện tại có sự cố. Box<T>
là loại tương thích DST, do đó, nó có thể được sử dụng làm vùng chứa cho đối tượng đặc điểm. Điều tương tự sẽ sớm đúng với Rc
và các con trỏ thông minh khác khi this RFC được triển khai. Tuy nhiên, trong trường hợp này không có sự ép buộc từ một loại bê tông đến một đối tượng đặc điểm vì Box<Duck>
nằm bên trong các lớp bổ sung của các loại (Rc<RefCell<..>>
).
Hãy nhớ rằng, đối tượng đặc điểm là con trỏ chất béo, vì vậy, Box<Duck>
khác với kích thước Box<Quack>
. Do đó, về nguyên tắc, chúng không tương thích trực tiếp: bạn không thể chỉ lấy byte của Box<Duck>
và ghi chúng vào nơi Box<Quack>
được mong đợi. Rust thực hiện một chuyển đổi đặc biệt, tức là, nó lấy một con trỏ tới bảng ảo cho Duck
, tạo một con trỏ chất béo và ghi nó vào biến số Box<Quack>
.
Khi bạn có Rc<RefCell<Box<Duck>>>
, tuy nhiên, rustc sẽ cần phải biết cách xây dựng và hủy cấu trúc cả hai RefCell
và Rc
để áp dụng cùng một chuyển đổi con trỏ chất béo cho nội bộ của nó. Đương nhiên, bởi vì đây là những loại thư viện, nó không thể biết làm thế nào để làm điều đó. Điều này cũng đúng với bất kỳ loại trình bao bọc nào khác, ví dụ: Arc
hoặc Mutex
hoặc thậm chí Vec
. Bạn không mong đợi rằng có thể sử dụng Vec<Box<Duck>>
làm Vec<Box<Quack>>
, phải không?Cũng có một thực tế là trong ví dụ với Rc
các Rcs được tạo ra từ Box<Duck>
và Box<Quack>
sẽ không được kết nối - chúng sẽ có các bộ tham chiếu khác nhau.
Tức là, chuyển đổi từ kiểu bê tông sang đối tượng đặc điểm chỉ có thể xảy ra nếu bạn có quyền truy cập trực tiếp vào con trỏ thông minh hỗ trợ DST, chứ không phải khi nó ẩn trong cấu trúc khác.
Điều đó nói rằng, tôi thấy cách có thể là có thể cho phép điều này cho một vài loại lựa chọn. Ví dụ, chúng tôi có thể giới thiệu một số loại đặc điểm Construct
/Unwrap
được biết đến với trình biên dịch và nó có thể sử dụng để "tiếp cận" bên trong một chồng trình bao bọc và thực hiện chuyển đổi đối tượng đặc điểm bên trong chúng. Tuy nhiên, không ai thiết kế điều này và cung cấp một RFC về nó được nêu ra - có lẽ bởi vì nó không phải là một tính năng cần thiết rộng rãi.
Lưu ý: 'RefCell' là không cần thiết ở đây, tôi có thể tạo lại vấn đề với' Rc> '. –
Matthieu, bạn là chính xác. 'RefCell' là không cần thiết để làm cho lỗi xảy ra. Dựa trên câu trả lời của Vladimir dưới đây, tôi có thể thấy lý do tại sao cùng một lỗi xảy ra có hoặc không có 'RefCell'. – rlkw1024