2017-10-07 76 views
3

我有一個實施的下列草圖:如何調用在盒裝特質對象上消耗自我的方法?

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(); 
} 

我可以有Transaction s的對他們的聽衆,將調用監聽器當事情發生在該交易。由於Listener是一個特徵,我存儲Vec<Box<Listener>>

我很難實現commitTransaction。不知何故,我必須通過在每個存儲的Listener上調用commit來消費這些盒子,但據我所知,我無法將盒子移出盒子。

我會如何消費我的聽衆提交?

+0

將「東西」移出盒子很容易; [你只需解除引用](https://stackoverflow.com/questions/42264041/how-do-i-get-an-owned-value-out-of-a-box)。你的情況更復雜,因爲你不再知道存儲箱內存儲的值有多大。這意味着你會收到一個錯誤:*無法移動類型監聽器的值:監聽器的大小不能靜態確定*。 – Shepmaster

回答

3

commit應用於裝箱對象是不允許的,因爲特質對象不知道它的大小(並且它在編譯時不是常量)。既然你打算使用監聽器對盒裝的對象,你可以做的是承認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"); 
    } 
} 

這使得Transaction編譯你寫的,因爲裏面的FooListener的實現Self的大小是衆所周知的,並且完全有可能將對象從盒子中移出並消耗兩者。

該解決方案的價格是Listener::commit現在要求 a Box。如果這是不可接受的,則可以在特徵中聲明commit(self)commit_boxed(self: Box<Self>),要求所有類型都實現兩者,可能使用私有函數或宏以避免代碼重複。這不是非常優雅,但它可以同時滿足盒裝和非盒裝用例,而不會損失性能。

相關問題