我正在尝试调用一个函数,该函数获取指向某个特征对象的Mutex
的指针,并且我希望能够为该特征对象的Mutex
实现特征以允许处理Mutex
作为抽象特征对象的一个实例。
举一个这样的例子,假设一个Event
监听器设置如下:
use std::sync::{Arc, Mutex, Weak};
// Define a simple event
trait Event: Send + Sync + 'static {}
impl Event for String {}
// Define the listener interface
trait Listener<E: Event> {
fn notify(&self, event: &E);
}
// Extend the listener interface to listenrs wrapped by a mutex
impl<E: Event> Listener<E> for Mutex<Listener<E>> {
fn notify(&self, event: &E) {
self.lock().unwrap().notify(event);
}
}
// Contrived thing to listen for messages
struct Console;
impl Listener<String> for Console {
fn notify(&self, event: &String) {
println!("{}", event);
}
}
// Simple function which may be called asynchronously and then sends a message
// when it is complete
fn do_stuff(l: Arc<Listener<String>>) {
// Would normally cast to a Weak<...> and then store in a list of listneners
// For some sort of object
let m = String::from("I did stuff!");
l.notify(&m);
}
fn main() {
let l: Arc<Mutex<Console>> = Arc::new(Mutex::new(Console));
let t1 = Arc::clone(&l) as Arc<Mutex<Listener<String>>>; //this part is ok
// Here is where we run into issues... This *should* be equvlient to
// do_stuff(t1), but with the corercion explicit
let t2 = Arc::clone(&t1) as Arc<Listener<String>>;
do_stuff(t2);
// This is a simple, working example of it interpreting a Mutex<Listener<E>>
// as just a Listener<E>
let m = String::from("Somthing else...");
(l as Arc<Mutex<Listener<String>>>).notify(&m);
}
问题是:
error[E0277]: the trait bound `Listener<std::string::String>: std::marker::Sized` is not satisfied in `std::sync::Mutex<Listener<std::string::String>>`
--> src/main.rs:45:14
|
45 | let t2 = Arc::clone(&t1) as Arc<Listener<String>>;
| ^^^^^^^^^^^^^^^ `Listener<std::string::String>` does not have a constant size known at compile-time
|
= help: within `std::sync::Mutex<Listener<std::string::String>>`, the trait `std::marker::Sized` is not implemented for `Listener<std::string::String>`
= note: required because it appears within the type `std::sync::Mutex<Listener<std::string::String>>`
= note: required for the cast to the object type `Listener<std::string::String>`
为什么会这样?由于Arc
是指向数据的指针,根据我的理解,它应该能够指向恰好是Listener<String>
的{{1}}。
我看到至少有两种方法可以避免这种情况,第一种方法是简单地Listener<Mutex<String>>
,但是,在实际代码中,这可能需要相互依赖,应该避免,因为特征只能在特征或结构的地方实现已定义(并且我的代码中未定义impl Listener<String> for Mutex<Listener<String>>
)。
第二种是将Mutex
移动到Mutex
对象中,以便调用者根本不需要将其转换为Listener
。这可行,也可能是更好的解决方案。尽管如此,我很好奇为什么提出的铸造不起作用,或者为了使它起作用可以改变什么。
答案 0 :(得分:5)
由于
Arc
是指向数据的指针,根据我的理解,它应该能够指向Listener<String>
是的,那是真的。我相信你的问题是你(不小心?)要求你在某个时候有Mutex<Listener<String>>
。这是不有效,因为Mutex
内的值不在指针后面,从而使整个类型不合格。
虽然有Arc<Mutex<Listener<String>>>
可以。
相反,我实现了Mutex
任何类型的特征,它实现了相同的特征。我也会对特征的引用和Box
ed特征对象做同样的事情。在所有情况下,我都会删除Sized
绑定以允许特征对象:
use std::sync::{Arc, Mutex};
trait Event: Send + Sync + 'static {}
impl Event for String {}
trait Listener<E: Event> {
fn notify(&self, event: &E);
}
impl<L, E> Listener<E> for Mutex<L>
where
L: ?Sized + Listener<E>,
E: Event,
{
fn notify(&self, event: &E) {
self.lock().unwrap().notify(event);
}
}
impl<'a, L, E> Listener<E> for &'a L
where
L: ?Sized + Listener<E>,
E: Event,
{
fn notify(&self, event: &E) {
(**self).notify(event);
}
}
struct Console;
impl Listener<String> for Console {
fn notify(&self, event: &String) {
println!("{}", event);
}
}
fn do_stuff(l: Arc<Listener<String>>) {
let m = String::from("I did stuff!");
l.notify(&m);
}
fn main() {
let l: Arc<Mutex<Console>> = Arc::new(Mutex::new(Console));
let l2 = Arc::clone(&l) as Arc<Listener<String>>;
let l3 = Arc::clone(&l) as Arc<Listener<String>>;
do_stuff(l);
do_stuff(l2);
let m = String::from("Something else...");
l3.notify(&m);
}