В: Могу ли я принять Box<dyn Error + Send>
в местах, которые принимают Box<dyn Error>
?
A: Да, с упаковкой нового типа. Решение, которое я наконец-то нашел, заключалось в следующем: ( Детская площадка )
use std::error::Error as StdError;
use std::result::Result as StdResult;
use std::fmt;
type Result = StdResult<(), Box< dyn StdError >>;
type SndResult = StdResult<(), Box< dyn StdError + Send >>;
fn fn_returning_result() -> Result { dbg!(Err("oops".into())) }
fn fn_returning_sndresult() -> SndResult { dbg!(Ok(())) }
/// Result type using `Er` defined below.
type Rt<T = ()> = StdResult<T, Er>;
// Error wrapper
#[derive(Debug)]
struct Er(Box<dyn StdError>);
impl fmt::Display for Er {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
impl StdError for Er {}
// Allow `?` operator
impl From<Box<dyn StdError>> for Er {
fn from(err: Box<dyn StdError>) -> Self {
Er(err)
}
}
impl From<Box<dyn StdError + Send>> for Er {
fn from(err: Box<dyn StdError + Send>) -> Self {
Er(err)
}
}
// List of callbacks
struct Callbacks<'a>(Vec<Box<dyn FnOnce() -> Rt + 'a>>);
impl<'a> Callbacks<'a> {
fn new() -> Self {
Callbacks(Vec::new())
}
fn add(&mut self, cb: impl FnOnce() -> Rt + 'a) {
self.0.push(Box::new(cb));
}
fn pop_and_call(&mut self) -> Rt {
self.0.pop().unwrap()()
}
}
// Example
fn main() -> Result {
let mut callbacks = Callbacks::new();
callbacks.add(|| { Ok(fn_returning_result()?) });
callbacks.add(|| { Ok(fn_returning_sndresult()?) });
callbacks.pop_and_call()?;
callbacks.pop_and_call()?;
Ok(())
}
Обратите внимание, что обратные вызовы могут использовать ?
для значений Result
или SndResult
(благодаря признаку From
), и что их возвращаемые значения также действительны Result
s, что позволяет main
также использовать ?
в своих вызовах (благодаря признаку StdError
impl).