首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在接受`Box<dyn Error>`的地方接受`Box<dyn Error + Send>`?

如何在接受`Box<dyn Error>`的地方接受`Box<dyn Error + Send>`?
EN

Stack Overflow用户
提问于 2019-05-28 02:12:09
回答 2查看 763关注 0票数 2

我可以在接受Box<dyn Error>的地方接受Box<dyn Error + Send>吗?如果是,是如何实现的?如果没有,为什么?有没有比下面的例子更优雅的方法?

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

EN

回答 2

Stack Overflow用户

发布于 2019-05-28 02:44:33

这是基于我通过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);
票数 0
EN

Stack Overflow用户

发布于 2019-05-29 06:36:12

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

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特征的隐含),并且它们的返回值也是有效的Result,这允许main在调用时也使用? (这要归功于StdError特征的隐含)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56330705

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档