如何匹配特质实现者

2024-05-05

我有一个由某些结构实现的特征。我想编写一个模式匹配,可以处理每种可能的情况:

trait Base {}

struct Foo {
    x: u32,
}
struct Bar {
    y: u32,
}

impl Base for Foo {}
impl Base for Bar {}

fn test(v: bool) -> Box<Base + 'static> {
    if v {
        Box::new(Foo { x: 5 })
    } else {
        Box::new(Bar { y: 10 })
    }
}

fn main() {
    let f: Box<Base> = test(true);

    match *f {
        Foo { x } => println!("it was Foo: {}!", x),
        Bar { y } => println!("it was Bar: {}!", y),
    }
}

()

我收到此编译错误:

error[E0308]: mismatched types
  --> src/main.rs:25:9
   |
25 |         Foo { x } => println!("it was Foo: {}!", x),
   |         ^^^^^^^^^ expected trait Base, found struct `Foo`
   |
   = note: expected type `dyn Base`
              found type `Foo`

error[E0308]: mismatched types
  --> src/main.rs:26:9
   |
26 |         Bar { y } => println!("it was Bar: {}!", y),
   |         ^^^^^^^^^ expected trait Base, found struct `Bar`
   |
   = note: expected type `dyn Base`
              found type `Bar`

你不能。 Traits 不支持向下转型 - Rust 不是基于继承/子类型的语言,它为您提供了另一组抽象。此外,你想做的事情是不合理的 - 特征是开放的(每个人都可以为任何事情实现它们),所以即使在你的情况下match *f涵盖了所有可能的情况,一般来说编译器无法知道这一点。

这里你有两个选择。如果您提前知道实现您的特征的结构集,只需使用枚举,它是一个完美的工具。它们允许您静态匹配一组封闭的变体:

enum FooBar {
    Foo(u32),
    Bar(u32),
}

fn test(v: bool) -> FooBar {
    if v {
        FooBar::Foo(5)
    } else {
        FooBar::Bar(10)
    }
}

fn main() {
    let f: FooBar = test(true);

    // Now that we have a `Box<Base>` (`*f` makes it a `Base`),
    // let's handle different cases:
    match f {
        FooBar::Foo(x) => println!("it was Foo: {}!", x),
        FooBar::Bar(y) => println!("it was Bar: {}!", y),
    }
}

()

这是迄今为止最简单的方法,并且应该始终是首选方法。

另一种方法是使用Any http://doc.rust-lang.org/std/any/特征。它是一种从特征对象到常规类型的类型安全向下转换的工具:

use std::any::Any;

struct Foo {
    x: u32,
}
struct Bar {
    y: u32,
}

fn test(v: bool) -> Box<Any + 'static> {
    if v {
        Box::new(Foo { x: 5 })
    } else {
        Box::new(Bar { y: 10 })
    }
}

fn main() {
    let f: Box<Any> = test(true);

    match f.downcast_ref::<Foo>() {
        Some(&Foo { x }) => println!("it was Foo: {}!", x),
        None => match f.downcast_ref::<Bar>() {
            Some(&Bar { y }) => println!("it was Bar: {}!", y),
            None => unreachable!(),
        },
    }

    // it will be nicer when `if let` lands
    //    if let Some(ref Foo { x }) = f.downcast_ref::<Foo>() {
    //        println!("it was Foo: {}!", x);
    //    } else if let Some(ref Bar { y }) = f.downcast_ref::<Bar>() {
    //        println!("it was Bar: {}!", y);
    //    } else { unreachable!() }
}

()

理想情况下应该可以写成这样:

trait Base: Any {}

impl Base for Foo {}
impl Base for Bar {}

然后使用Base在代码中,但现在无法完成,因为特征继承不适用于特征对象(例如,不可能从Box<Base> to Base<Any>).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何匹配特质实现者 的相关文章

随机推荐