Mil*_*ndt 3 traits rust trait-objects
我正在编写一些代码,并且有一个带有self按值获取方法的特征。我想在一个Box'd trait 对象上调用这个方法(消耗Box和它的值)。这可能吗?如果是这样,如何?
在代码方面,一个最小的例子看起来像以下(不完整的)代码:
trait Consumable {
fn consume(self) -> u64;
}
fn consume_box(ptr: Box<dyn Consumable>) -> u64 {
//what can I put here?
}
Run Code Online (Sandbox Code Playgroud)
我的问题是如何在功能填补consume_box与指定的签名,以便值返回的任何值将通过调用得到consume的Box“d值。
我最初写的
ptr.consume()
Run Code Online (Sandbox Code Playgroud)
作为函数的主体,虽然我意识到这不是一个正确的想法,因为它没有理解我想要Box被消耗的事实,而不仅仅是它的内容,但这是我唯一能想到的. 这不会编译,给出一个错误:
无法移动 dyn Consumable 类型的值:无法静态确定 dyn Consumable 的大小
这对我来说有点令人惊讶,我是 Rust 的新手,我曾想过可能self参数的传递类似于 C++ 中的右值引用(这确实是我想要的 - 在 C++ 中,我可能会通过带有签名的方法来实现它virtual std::uint64_t consume() &&,让std::unique_ptr通过虚拟析构函数清理移动的对象),但我猜 Rust 确实是按值传递,将参数移动到位之前 - 所以它拒绝代码是合理的。
问题是,我不确定如何获得我想要的行为,在那里我可以使用Box'd trait 对象。我尝试使用默认实现向 trait 添加一个方法,认为这可能会让我在 vtable 中得到一些有用的东西:
trait Consumable {
fn consume(self) -> u64;
fn consume_box(me: Box<Self>) -> u64 {
me.consume()
}
}
Run Code Online (Sandbox Code Playgroud)
但是,这会产生错误
特性
Consumable不能被做成一个对象
当我提到Box<dyn Consumable>类型时 - 这并不奇怪,因为编译器弄清楚如何处理参数类型随 变化的函数Self会是奇迹。
是否可以consume_box使用提供的签名实现该功能- 甚至在必要时修改特征?
如果它有用,更具体地说,这是某些数学表达式的一种表示形式的一部分 - 也许玩具模型是大致如下所示的特定实现:
impl Consumable for u64 {
fn consume(self) -> u64 {
self
}
}
struct Sum<A, B>(A, B);
impl<A: Consumable, B: Consumable> Consumable for Sum<A, B> {
fn consume(self) -> u64 {
self.0.consume() + self.1.consume()
}
}
struct Product<A, B>(A, B);
impl<A: Consumable, B: Consumable> Consumable for Product<A, B> {
fn consume(self) -> u64 {
self.0.consume() * self.1.consume()
}
}
fn parse(&str) -> Option<Box<dyn Consumable> > {
//do fancy stuff
}
Run Code Online (Sandbox Code Playgroud)
在大多数情况下,事物是普通的旧数据(但可能是由于泛型而造成的任意大块),但也要使其与传递更多不透明句柄到此类事物兼容 - 因此需要能够与Box<dyn Consumable>. 至少在语言层面,这是一个很好的模型,说明我在做什么——这些对象拥有的唯一资源是内存片段(与多线程无关,也没有自我引用的恶作剧)——尽管这模型没有捕捉到我所拥有的用例是一个对实现使用对象而不是仅仅读取它很有用的用例,也没有适当地建模我想要一个“开放”enum 直接代表一棵树)-因此为什么我要询问按值传递而不是尝试重写它以按引用传递。
目前不支持此功能。甲dyn Consumable表示未施胶型其除了通过间接非常有限的(通过引用或Box样结构)。
然而,有RFC 1909: Unsized RValues希望放宽其中一些限制。能够传递未定义大小的函数参数,就像self在这种情况下一样。此 RFC 的当前实现在每晚编译时接受您的初始代码unsized_fn_params:
#![feature(unsized_fn_params)]
trait Consumable {
fn consume(self) -> u64;
}
struct Foo;
impl Consumable for Foo {
fn consume(self) -> u64 {
42
}
}
fn main () {
let ptr: Box<dyn Consumable> = Box::new(Foo);
println!("result is {}", ptr.consume());
}
Run Code Online (Sandbox Code Playgroud)
在操场上看到。
| 归档时间: |
|
| 查看次数: |
988 次 |
| 最近记录: |