我正在实现一个Rust库,它需要一个异步MPSC通道,但是,我不想依赖于任何特定的async
运行时(例如tokio
、smol
),我想让库的用户 Select 使用哪个运行时,所以我定义了一些特征:
struct Job { ... }
trait Sender {
fn send(&mut self, job: Job);
}
trait Receiver {
fn recv(&mut self) -> Future<Output = Option<Job>>;
}
fn foo(tx: impl Sender, rx: impl Receiver) {
// ...
}
然而,库用户必须在实际使用的运行时创建大量包装器,例如为Tokio:
// We have to create wrappers here, as both `mylib::Sender`
// and `tokio::Sender` are from third party libraries, we
// cannot implement `mylib::Sender` for `tokio::Sender` directly.
struct TokioSender(tokio::Sender);
struct TokioReceiver(tokio::Receiver);
impl mylib::Sender for TokioSender { ... }
impl mylib::Receiver for TokioReceiver { ... }
// Finally we can call the library function.
fn run() {
...
let (tx, rx) = tokio::channel();
mylib::foo(TokioSender(tx), TokioReceiver(rx));
...
}
如果特征有很多功能,包装器可能会很繁琐.在围棋中,如果类型T
具有接口I
定义的所有函数,则T
实现I
,并且可以在所需类型为I
的地方传递,而不需要任何额外的努力.那么,有没有可能在这里做同样的事情,让所有具有由特征定义的函数的T
自动实现像GO这样的特征,这样我们就不再需要那些包装器了?
或者可能有任何其他解决办法?