Я пытаюсь вызвать функцию, которая принимает указатель на 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>
, который оказывается Listener<Mutex<String>>
.
Я вижу по крайней мере два способа избежать этого, первый — просто impl Listener<String> for Mutex<Listener<String>>
, однако в реальном коде это может потребовать взаимозависимости, которой следует избегать, поскольку трейт может быть реализован только там, где определен трейт или структура (а Mutex
не определена). определено в моем коде).
Второй — переместить Mutex
в объект Listener
, чтобы вызывающему объекту вообще не нужно было приводить его. Это сработает и может быть лучшим решением. Несмотря на это, мне любопытно, почему предложенный кастинг не работает и что можно изменить, чтобы заставить его работать.