![](/img/trans.png)
[英]How do you convert a Box<dyn Trait> to a Rc<dyn Trait>?
[英]How do you create a Box<dyn Trait>, or a boxed unsized value in general?
我有以下代碼
extern crate rand;
use rand::Rng;
pub struct Randomizer {
rand: Box<Rng>,
}
impl Randomizer {
fn new() -> Self {
let mut r = Box::new(rand::thread_rng()); // works
let mut cr = Randomizer { rand: r };
cr
}
fn with_rng(rng: &Rng) -> Self {
let mut r = Box::new(*rng); // doesn't work
let mut cr = Randomizer { rand: r };
cr
}
}
fn main() {}
它抱怨說
error[E0277]: the trait bound `rand::Rng: std::marker::Sized` is not satisfied
--> src/main.rs:16:21
|
16 | let mut r = Box::new(*rng);
| ^^^^^^^^ `rand::Rng` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `rand::Rng`
= note: required by `<std::boxed::Box<T>>::new`
我不明白為什么當Box<T>
沒有將其強加給T
時,它需要在Rng
上Rng
Sized
。
關於Sized
trait 和 bound 的更多信息 - 這是一個相當特殊的 trait,它被隱式添加到每個函數中,這就是為什么你看不到它在Box::new
的原型中列出的原因:
fn new(x: T) -> Box<T>
請注意,它按值(或移動)取x
,因此您甚至需要知道調用該函數的大小。
相比之下, Box
型本身並不需要Sized
; 它使用(再次特殊的)特征綁定?Sized
,這意味着“選擇退出默認的Sized
綁定”:
pub struct Box<T> where T: ?Sized(_);
如果你仔細看看,有一種方法可以創建一個無大小類型的Box
:
impl<T> Box<T> where T: ?Sized
....
unsafe fn from_raw(raw: *mut T) -> Box<T>
因此,從不安全的代碼中,您可以從原始指針創建一個。 從那時起,一切正常。
問題其實很簡單:你有一個 trait 對象,關於這個 trait 對象你只知道兩件事:
當您請求將此對象移動到不同的內存位置(在堆上)時,您會丟失一個關鍵信息:它的大小。
你怎么知道應該保留多少內存? 要移動多少位?
當對象為Sized
,此信息在編譯時是已知的,因此編譯器會為您“注入”它。 然而,在 trait-object 的情況下,這個信息是未知的(不幸的是),因此這是不可能的。
使這些信息可用並提供多態移動/克隆可用將非常有用,但這還不存在,到目前為止我不記得有任何建議,我不知道成本是多少(就維護,運行時間懲罰,...)。
我也想發布答案,處理這種情況的一種方法是
fn with_rng<TRand: Rng>(rng: &TRand) -> Self {
let r = Box::new(*rng);
Randomizer { rand: r }
}
Rust 的單態性將創建with_rng
的必要實現,用具體大小的類型替換TRand
。 此外,您可以添加需要TRand
為Sized
的 trait bound。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.