rust - 特质有时可以移动
问题描述
我有一个看起来像的特质
trait Trait<T>
where T: Data
{
fn m1(&self) -> bool;
fn m2(self) -> Box<dyn Trait<T>>;
}
为什么甚至允许m2
方法?self
它不像任何 trait impls 都可以调用该方法,因为:
cannot move a value of type dyn Trait<T>: the size of dyn Trait<T> cannot be statically determined
这个错误是有道理的,但为什么我可以像这样push
在容器中描述对象Vec
:
let trait_object: Box<dyn Trait<T>> = e;
let mut new_vec = Vec::new();
new_vec.push(trait_object)
那么如果特征对象无法移动,为什么会new_vec.push(trait_object)
起作用?
解决方案
dyn Trait<T>
是一个 trait 对象,它不同于具有实现该 trait 的约束类型变量。
特征对象使用动态分派并且在编译时不知道大小 - 这就是为什么您几乎总是在&
引用或装箱后看到特征对象的原因。这就是错误消息显示的原因the size of dyn Trait<T> cannot be statically determined
。
您的 trait 可以为任何具体的 ( Sized
) 类型实现。例如,对于i32
:
impl Trait<String> for i32
where
T: Data,
{
fn m1(&self) -> bool {
true
}
// Can take self here because i32 is Sized
fn m2(self) -> Box<dyn Trait2<T>> {
make_boxed_trait_t(String::new())
}
}
为什么我可以像这样
push
在容器中描述对象Vec
:
这是有效的,因为您的示例中的特征对象是装箱的。dyn Trait<T>
没有大小,但Box<dyn Trait<T>>
在编译时有一个已知的大小。大小是两个指针的大小,因为装箱的 trait 对象的布局始终是指向数据的指针和指向类型实现的 vtable 的指针Trait
。
推荐阅读
- odoo - 如何在现有记录 odoo 上运行计算
- xcode - Xcode 上的 Flutter 应用程序升级后无法启动
- angular - 从 canActivate 导航时的角度路由器无限循环
- mjml - 如何在 MJML 中使用 php 变量
- r - 计算面板中 os 个人的数量以及他们在面板中出现的次数
- javascript - 从对应于 Key 的 JSON 角度提取数据
- c++ - C++:安全使用 vsprintf
- javascript - 如何根据另一个自动完成字段清除自动完成材料 ui 字段?
- shell - Jenkins 将参数作为 env 传递给 shell 脚本,以将 sh 传递给 kubernetes pod
- node.js - 当我在 eggjs 模型的“findAll”函数中使用“Op.notLike”时,如何避免转义字符 \"?