Rust 如何调用在装箱的trait对象上使用self的方法?

Rust 如何调用在装箱的trait对象上使用self的方法?,rust,ownership-semantics,Rust,Ownership Semantics,我有一个实现的草图: trait Listener { fn some_action(&mut self); fn commit(self); } struct FooListener {} impl Listener for FooListener { fn some_action(&mut self) { println!("{:?}", "Action!!"); } fn commit(self) {

我有一个实现的草图:

trait Listener {
    fn some_action(&mut self);
    fn commit(self);
}

struct FooListener {}

impl Listener for FooListener {
    fn some_action(&mut self) {
        println!("{:?}", "Action!!");
    }

    fn commit(self) {
        println!("{:?}", "Commit");
    }
}

struct Transaction {
    listeners: Vec<Box<Listener>>,
}

impl Transaction {
    fn commit(self) {
        // How would I consume the listeners and call commit() on each of them?
    }
}

fn listener() {
    let transaction = Transaction {
        listeners: vec![Box::new(FooListener {})],
    };
    transaction.commit();
}
trait侦听器{
fn一些动作(多个自我);
fn承诺(自我);
}
结构愚笨者{}
傻瓜监听器的impl监听器{
fn某些操作(&mut self){
println!(“{:?}”,“Action!!”;
}
fn提交(自我){
println!(“{:?}”,“提交”);
}
}
结构事务{
听众:Vec,,
}
impl事务{
fn提交(自我){
//如何使用侦听器并对每个侦听器调用commit()?
}
}
fn侦听器(){
让交易=交易{
监听器:vec![Box::new(傻瓜监听器{}],
};
commit();
}
我可以让
Transaction
s上有监听器,当该事务发生某些事情时,这些监听器将调用监听器。因为
Listener
是一种特性,所以我存储了一个
Vec

对于
事务
,我很难实现
提交
。不知何故,我必须通过调用每个存储的
侦听器上的
commit
来消耗盒子,但据我所知,我无法将东西移出盒子


提交时如何使用侦听器?

不允许将
commit
应用于已装箱的对象,因为trait对象不知道其大小(并且在编译时它不是常量)。由于您计划将侦听器用作装箱对象,因此您可以做的是确认将在箱子上调用
commit
,并相应地更改其签名:

trait Listener {
    fn some_action(&mut self);
    fn commit(self: Box<Self>);
}

struct FooListener {}

impl Listener for FooListener {
    fn some_action(&mut self) {
        println!("{:?}", "Action!!");
    }

    fn commit(self: Box<Self>) {
        println!("{:?}", "Commit");
    }
}
trait侦听器{
fn一些动作(多个自我);
fn提交(self:Box);
}
结构愚笨者{}
傻瓜监听器的impl监听器{
fn某些操作(&mut self){
println!(“{:?}”,“Action!!”;
}
fn提交(self:Box){
println!(“{:?}”,“提交”);
}
}
这使
Transaction
能够在编写时进行编译,因为在
woulListener
的实现中,
Self
的大小是众所周知的,完全可以将对象移出框中并同时使用这两个对象

此解决方案的价格是,
Listener::commit
现在需要一个
。如果这是不可接受的,您可以在trait中声明
commit(self)
commit\u boxed(self:Box)
,要求所有类型都实现这两个功能,可能使用私有函数或宏来避免代码重复。这不是很优雅,但它可以在不损失性能的情况下满足装箱和未装箱的用例。

启用此功能后,自然代码:


把“东西”从盒子里拿出来很容易。您的情况更复杂,因为您不再知道存储在盒子中的值有多大。这意味着您将遇到一个错误:无法移动Listener类型的值:无法静态确定Listener的大小。这是否适用于trait对象?比如,如果我有一个
letbox:box
,我可以调用
box.commit()?我这样问是因为
Self
将成为一个愚蠢的听者,而不是听者,对吗?@Lucretiel是的,答案(很可能是这个问题)是在考虑特质对象的情况下写的。
// 1.37.0-nightly 2019-06-03 6ffb8f53ee1cb0903f9d
#![feature(unsized_locals)]

// ...

impl Transaction {
    fn commit(self) {
        for l in self.listeners {
            l.commit()
        }
    }
}