rust - 如何共享堆分配的特征对象?
问题描述
我有一个特征和一个实现该特征的结构(一个特征对象)。我想在堆上分配我的特征对象并让其他结构引用它们。
框字段
trait Material {}
struct Iron {}
impl Material for Iron {}
// It works, but takes ownership of boxes.
struct Sphere {
radius: f64,
material: Box<dyn Material>,
}
这段代码有效,但我不能让两个球体共享相同的Material
,因为Box
拥有材料,球体拥有它的Box
场。
参考字段
我的下一个尝试是使用普通参考而不是Box
:
struct Sphere<'a> {
radius: f64,
material: &'a dyn Material,
}
这也有效,但据我了解,我Material
的 s 将分配在堆栈而不是堆上。如果Material
值真的很大而且我宁愿把它放在堆上怎么办?这导致我采用下一种无法编译的方法:
引用框
struct Sphere<'a> {
radius: f64,
material: &'a Box<dyn Material>,
}
fn main() {
let m1 = &Box::new(Iron {});
let s1 = Sphere {
radius: 1.0,
material: m1,
};
assert_eq!(s1.radius, 1.0);
}
这给了我以下错误:
error[E0308]: mismatched types
--> src/main.rs:16:19
|
16 | material: m1,
| ^^ expected trait Material, found struct `Iron`
|
= note: expected type `&std::boxed::Box<(dyn Material + 'static)>`
found type `&std::boxed::Box<Iron>`
我不太确定'static
该类型的来源,并且看起来它混淆了类型检查器。否则dyn Material
,Iron
据我所知可以统一。
解决方案
Rc
或者Arc
当您需要共享所有权时,Rc
或者Arc
通常是第一个使用的工具。这些类型通过引用计数实现共享,因此克隆一个很便宜(只需复制一个指针并增加 refcount)。在这种情况下,两者都可以轻松工作:
struct Sphere {
radius: f64,
material: Rc<dyn Material>,
}
let m1 = Rc::new(Iron {});
let s1 = Sphere {
radius: 1.0,
material: m1,
};
m1
是具体的类型Rc<Iron>
,但因为它实现了traitCoerceUnsized
,它可以在期望. 您可以通过ing使多个s 引用相同的材料。(完整示例)Rc<dyn Material>
Sphere
clone
m1
Rc
和之间的区别在于Arc
它Arc
可以安全地用于多个线程之间的共享,但Rc
不是。(另请参阅何时使用 Rc 与 Box?)
参考
至于您的参考示例:
这也有效,但据我了解,我的材料将分配在堆栈而不是堆上。
确实,生命周期是从堆栈派生的,但引用本身并不需要指向堆栈上的某些东西。例如,您可以通过取消引用来引用T
a中的:Box<T>
Box
struct Sphere<'a> {
radius: f64,
material: &'a dyn Material,
}
let m1 = Box::new(Iron {});
let s1 = Sphere {
radius: 1.0,
material: &*m1, // dereference the `Box` and get a reference to the inside
};
let s2 = Sphere {
radius: 2.0,
material: &*m1,
};
这甚至比使用更便宜,Rc
因为&
引用是Copy
可以的,但是即使它Iron
本身存储在堆上,指向它的引用仍然绑定到堆栈变量的生命周期m1
。如果你不能使m1
寿命足够长,你可能想要使用Rc
而不是简单的引用。
参考一个Box
这种方法也应该有效,尽管它是不必要的。它不这样做的原因是,尽管您可以将 a 强制Box<Iron>
为 a Box<dyn Material>
,但您不能将 a强制&Box<Iron>
为 a &Box<dyn Material>
;类型不兼容。相反,您需要创建一个类型的堆栈变量,Box<dyn Material>
以便您可以引用它。
let m1: Box<dyn Material> = Box::new(Iron {}); // coercion happens here
let s1 = Sphere {
radius: 1.0,
material: &m1, // so that this reference is the right type
};
推荐阅读
- python - 在 pandas 中使用 np.where 将值设置为移位值
- django - 通过 CreateView 类提交表单时如何访问模板中的 OneToOne 字段
- python - Matplotlib plt.plot() 在 anaconda 中不起作用
- aws-lambda - 无服务器调用有效,但 curl 给出错误
- excel - 净推荐值 (NPS) 的回归分析
- eclipse - 脚本异步延迟未定义的属性名称
- appium - 如何为动态屏幕获取 UI Automator 转储
- javascript - 设置文本
- c# - 立即删除通过 SqlBulkCopy.WriteToServer 插入的记录
- ruby-on-rails - 我的路线文件与预期结果不符