如何使用Arc <Mutex <... >>投射特征对象?

Ead*_*ord 2 smart-pointers traits rust

我试图调用一个函数,该函数接受一个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);
}
Run Code Online (Sandbox Code Playgroud)

(游乐场)

问题是:

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>`
Run Code Online (Sandbox Code Playgroud)

为什么会这样?由于a Arc是指向数据的指针,根据我的理解,它应该能够指向Listener<String>恰好是a的数据Listener<Mutex<String>>.

我看到至少有两种方法可以避免这种情况,第一种方法是简单地impl Listener<String> for Mutex<Listener<String>>说,在实际的代码中,这可能需要相互依赖,这应该避免,因为特征只能在特征或结构被定义的地方实现(并且Mutex没有在我的代码).

第二种是将对象移动MutexListener对象中,这样调用者根本不需要对其进行转换.这可行,也可能是更好的解决方案.尽管如此,我很好奇为什么提出的铸造不起作用,或者为了使其起作用可以改变什么.

She*_*ter 5

由于a Arc是指向数据的指针,根据我的理解,它应该能够指向aListener<String>

是的,这是真的.我相信你的问题是你(不小心?)要求你Mutex<Listener<String>>在某个时刻.这是不是有效的,因为有里面的值Mutex不是指针后面,从而使整个型无胶.

Arc<Mutex<Listener<String>>>尽管如此,这很好.

相反,我会实现性状的Mutex任何实现相同特质的一种.我也会对特征的引用和Boxed特征对象做同样的事情.在所有情况下,我将删除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);
}
Run Code Online (Sandbox Code Playgroud)