首页 > 解决方案 > 使用“?”进行自动错误转换 自定义类型的运算符

问题描述

我正在努力理解?运营商的细微差别。采取以下代码:

链接到游乐场

use std::{error::Error as StdError, fmt};

#[derive(Debug)]
struct MyError(Box<dyn StdError>);

impl fmt::Display for MyError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}

impl StdError for MyError{}

impl From<Box<dyn StdError>> for MyError {
    fn from(err: Box<dyn StdError>) -> Self {
        MyError(err)
    }
}

#[derive(Debug)]
struct RandomErr(String);

impl fmt::Display for RandomErr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}

impl StdError for RandomErr{}

fn no_custom() -> Result<(), Box<dyn StdError>> {
    Err(RandomErr("hello there".to_owned()))?
}

// This fails to compile
fn custom() -> Result<(), MyError> {
    Err(RandomErr("hello there".to_owned()))?
}

我认为custom()应该编译。RandomError是 a StdError,所以RandomErr应该可以转换为 ,MyError因为有一个用于转换 from 的 impl StdError,不是吗?

标签: rusttype-conversiontraitstrait-objects

解决方案


我认为custom()应该编译。RandomError是 a StdError,所以RandomErr应该可以转换为 ,MyError因为有一个用于转换 from 的 impl StdError,不是吗?

没有。没有传递性From(或任何特征,据我所知)。Rustc 通常会按照你说的去做,而不是为了避免特征解析中的组合爆炸之类的问题。

因此,C: From<B>B: From<A>并不意味着/转换为C: From<A>,您可以编写简化的大小写并将达到 E0277(特征不满足):

struct A;
struct B;
struct C;

impl From<A> for B {
    fn from(a: A) -> Self { B }
}
impl From<B> for C {
    fn from(b: B) -> Self { C }
}

fn main() {
    let _: C = From::from(A);
}

推荐阅读