如何在接受`Box <dyn error =“”>`的地方接受`Box <dyn error =“” + =“” send =“”>`?

时间:2019-05-27 18:12:09

标签: rust

我可以在接受Box<dyn Error + Send>的地方接受Box<dyn Error>吗?如果是,怎么办?如果没有,为什么,并且比下面的示例有更优雅的方法吗?

#![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

2 个答案:

答案 0 :(得分:0)

这是基于Llaurence_给出的on Reddit答案:

通过将错误类型设置为通用,我可以更改register_callback以同时接受Box<dyn Error>Box<dyn Error + Send>错误:

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);

答案 1 :(得分:0)

问:我可以在接受Box<dyn Error + Send>的地方接受Box<dyn Error>吗?

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

请注意,回调可以在?Result值上使用SndResult(由于From特质隐含),并且它们的返回值是有效的{{以及1}},还允许Result在通话时也使用main(这要归功于?特质impl)。