Return 结果<Box<dyn Trait>> 在一场比赛中

Return Result<Box<dyn Trait>> in a match

我有一组实现给定特征的类型,我想从字符串名称中获取具体类型对象,奇怪的是,当我的 match returns Box<dyn Trait>但是当我将它包装在 Result.

中时却没有

鉴于此特征和类型:

trait Shape {
    fn edges(&self) -> u8;
}

struct Triangle {}

impl Shape for Triangle {
    fn edges(&self) -> u8 {
        3
    }
}

struct Rectangle {}

impl Shape for Rectangle {
    fn edges(&self) -> u8 {
        4
    }
}

这个有效:

fn get_shape_edges(name: &str) -> Result<u8, &str> {
    let shape: Box<dyn Shape> = match name {
        "triangle" => Box::new(Triangle {}),
        "rectangle" => Box::new(Rectangle {}),
        _ => panic!("Bad value"),
    };
    Ok(shape.edges())
}

然而这不是:

fn get_shape_edges(name: &str) -> Result<u8, &str> {
    let shape: Box<dyn Shape> = match name {
        "triangle" => Ok(Box::new(Triangle {})),
        "rectanble" => Ok(Box::new(Rectangle {})),
        _ => Err("bad value")
    }?;
    Ok(shape.edges())
}

错误:

error[E0308]: `match` arms have incompatible types
  --> src/main.rs:24:24
   |
22 |       let shape: Box<dyn Shape> = match name {
   |  _________________________________-
23 | |         "triangle" => Ok(Box::new(Triangle {})),
   | |                       ------------------------- this is found to be of type `Result<Box<Triangle>, _>`
24 | |         "rectanble" => Ok(Box::new(Rectangle {})),
   | |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Triangle`, found struct `Rectangle`
25 | |         _ => Err("bad value")
26 | |     }?;
   | |_____- `match` arms have incompatible types
   |
   = note: expected type `Result<Box<Triangle>, _>`
              found enum `Result<Box<Rectangle>, _>`

当然这只是一个例子,在我的代码中我想使用后一种情况来处理错误。

为什么后一种情况不起作用?

您需要将 Box 转换为 Box<dyn Shape>,否则编译器不够智能(仍然)无法忽略类型:

fn get_shape_edges(name: &str) -> Result<u8, &str> {
    let shape: Box<dyn Shape> = match name {
        "triangle" => Ok(Box::new(Triangle {}) as Box<dyn Shape>),
        "rectanble" => Ok(Box::new(Rectangle {}) as Box<dyn Shape>),
        _ => Err("bad value")
    }?;
    Ok(shape.edges())
}

Playground

顺便说一句,因为您已经在构建结果,所以您可以将 edges 映射到原始构建的结果:

fn get_shape_edges(name: &str) -> Result<u8, &str> {
    let shape = match name {
        "triangle" => Ok(Box::new(Triangle {}) as Box<dyn Shape>),
        "rectanble" => Ok(Box::new(Rectangle {}) as Box<dyn Shape>),
        _ => Err("bad value")
    };
    shape.map(|s| s.edges())
}