从 Container<Box<Dog>>
到
Container<Box<dyn Animal>>
//example
fn main() {
let container: Container<Box<Dog>> = Container(Box::new(Dog()));
let test: Container<Box<dyn Animal>> = container;
// expected struct `RcHash<Box<dyn Enity>>`
// found struct `RcHash<Box<Role>>`
let test = container as Container<Box<dyn Animal>>;
// non-primitive cast: `Container<Box<Dog>>` as `Container<Box<dyn Animal>>`
// an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
}
//struct
struct Container<T> (T);
struct Dog ();
//trait
trait Animal { fn echo(&self); }
impl Animal for Dog { fn echo(&self) { println!("dog"); } }
Box<Dog>
和 Box<dyn Animal>
之间进行简单的cast
,因为它们并不完全相同。两个
Box
都可以充当指向
Dog
实例的指针,但
Box<dyn Animal>
实际上将具有不同的size,因为特征对象还有一个额外的指针(对于 vtable)。我建议您阅读this以更好地理解有关特征对象的部分。 上述意味着你无法避免创建一个新的
Box<dyn Animal>
实例,因此你无法避免创建一个新的
Container<Box<dyn Animal>>
实例(因为如果
A != B
=>
Container<A> != Container<B>
/这里你可以将
!=
解释为“不兼容”或“不同的尺寸”/)。 这是一个如何从
Box<dyn Animal>
实例“手动”创建新
Box<Dog>
实例的示例:
let dog_box: Box<Dog> = Box::new(Dog());
let animal: Box<dyn Animal> = Box::new(*dog_box);
这基本上会移动小狗实例(而不是创建另一个克隆)。
这是您的案例的更完整示例:
let container: Container<Box<Dog>> = Container(Box::new(Dog()));
let cont_animal: Container<Box<dyn Animal>> = Container(Box::new(*container.0));
impl Trait for Something {
fn foo() -> Vec<Box<dyn Info>> {
let infos = json_parser
.get_info::<BiliInfo>("")? // get_info need T to use serde_json
.into_iter()
.map(|i| Box::new(i) as Box<dyn Info>)
.collect();
infos
}}
我认为当特质要求我们这样做时我们就需要这样做。在这种情况下,trait 的方法 foo
需要
infos
为
Box<dyn Info>
,但 serde_json 需要具体类型并且只能返回
BiliInfo
。定义特质时我们可以避免:
trait Trait {
type Info: Info;
fn foo() -> Self::Info;
}
这样可以避免使用Box
,但是由于我知识贫乏,不知道对性能或者其他方面的影响。