` 在接受 `Box 的地方`?,rust"/>

首页 > 解决方案 > 如何接受`Box` 在接受 `Box 的地方`?

问题描述

我可以在接受的Box<dyn Error + Send>地方接受 aBox<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(())
}

操场

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

另外,我想使用单个返回类型调用回调fn_returning_result()?或在回调内部调用,而无需执行.fn_returning_sndresult()?map_err

标签: rust

解决方案


问:我可以在接受的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(())
}

请注意,回调可以?在其中一个ResultSndResult值上使用(感谢Fromtrait impls),并且它们的返回值也是有效Result的,允许main也用于?他们的调用(感谢StdErrortrait impls)。


推荐阅读