【问题标题】:How to accept `Box<dyn Error + Send>` in places that accept `Box<dyn Error>`?如何在接受 `Box<dyn Error>` 的地方接受 `Box<dyn Error + Send>`?
【发布时间】:2019-05-27 18:12:08
【问题描述】:

我可以在接受Box&lt;dyn Error&gt; 的地方接受Box&lt;dyn Error + Send&gt; 吗?如果是,如何?如果不是,为什么?有没有比下面的例子更优雅的方法?

#![allow(unused)]

use std::error::Error as StdError;
use std::result::Result as StdResult;

type    Result = StdResult<(), Box< dyn StdError >>;
type SndResult = StdResult<(), Box< dyn StdError + Send >>;

fn fn_returning_result()    ->    Result { Ok(()) }
fn fn_returning_sndresult() -> SndResult { Ok(()) }

/// Accept a callback that returns a non-Send `Result`.
fn register_callback<CB: FnOnce() -> Result>(cb: CB) { /* ... */ }

fn main() -> Result {
    // Is there a way to get rid of ... vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv ... this part?
    let cb = || fn_returning_sndresult().map_err(|e| -> Box<dyn StdError> { e });
    register_callback(cb);

    Ok(())
}

Playground

编辑:我想在这里做的只是let cb = || fn_returning_sndresult();,但这不会编译。

另外,我想在回调中调用 fn_returning_result()?fn_returning_sndresult()? 并使用单一返回类型而不执行 map_err

【问题讨论】:

标签: rust


【解决方案1】:

这是基于我得到的 Llaurence_ on Reddit 的回答:

我可以更改 register_callback 以接受 Box&lt;dyn Error&gt;Box&lt;dyn Error + Send&gt; 错误,方法是使错误类型通用:

fn register_callback<CB, E>(cb: CB)
where
    CB: FnOnce() -> StdResult<(), Box<E>>,
    E: StdError + ?Sized,
{ /* ... */ }

现在我可以传递一个返回任一错误/结果的回调:

register_callback(fn_returning_result);
register_callback(fn_returning_sndresult);

【讨论】:

    【解决方案2】:

    问:我可以在接受Box&lt;dyn Error&gt; 的地方接受Box&lt;dyn Error + Send&gt; 吗?

    A:是的,有一些新类型的包装。我最终得到的解决方案是:(Playground)

    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(())
    }
    

    请注意,回调可以在ResultSndResult 值上使用?(感谢From trait impls),并且它们的返回值也是有效的Results,允许@987654330 @ 在他们的电话中也使用?(感谢StdError trait impl)。

    【讨论】:

      猜你喜欢
      • 2020-03-26
      • 1970-01-01
      • 1970-01-01
      • 2019-01-04
      • 2020-10-08
      • 2022-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多