解构枚举时是否可以向上转换为特征?

Is it possible to upcast to a trait when destructuring enums?

我希望能够 destructure/upcast 枚举常见特征的变体。这是设置:

trait SomeTrait {
    fn some_func(&self);
}

struct SomeStruct1;
impl SomeTrait for SomeStruct1 {
    fn some_func(&self) {}
}

struct SomeStruct2;
impl SomeTrait for SomeStruct2 {
    fn some_func(&self) {}
}

enum SomeEnum {
    Value1(SomeStruct1),
    Value2(SomeStruct2),
}

这是我尝试过的一种可能性:

fn call_some_func(some_enum: SomeEnum) {
    match some_enum {
        SomeEnum::Value1(ref some_trait: &SomeTrait) |
        SomeEnum::Value2(ref some_trait: &SomeTrait) => some_trait.some_func()
    }
}

它导致了这个错误:

error: expected one of `)`, `,`, or `@`, found `:`
  --> src/main.rs:22:40
   |
22 |         SomeEnum::Value1(ref some_trait: &SomeTrait) |
   |                                        ^ expected one of `)`, `,`, or `@` here

这是我的另一个想法:

fn call_some_func2(some_enum: SomeEnum) {
    match some_enum {
        _(ref some_trait: &SomeTrait) => some_trait.some_func()
    }
}

也失败了:

error: expected one of `=>`, `if`, or `|`, found `(`
  --> src/main.rs:22:10
   |
22 |         _(ref some_trait: &SomeTrait) => some_trait.some_func()
   |          ^ expected one of `=>`, `if`, or `|` her

有谁知道完成这种解构的方法吗?

不,你不能同时解构。你可以在 之后完成它:

// My preferred
fn call_some_func(some_enum: SomeEnum) {
    let x: &SomeTrait = match some_enum {
        SomeEnum::Value1(ref x) => x,
        SomeEnum::Value2(ref x) => x,
    };
    x.some_func();
}
// Also works
fn call_some_func(some_enum: SomeEnum) {
    let x = match some_enum {
        SomeEnum::Value1(ref x) => x as &SomeTrait,
        SomeEnum::Value2(ref x) => x,
    };
    x.some_func();
}

我鼓励您将其提取到一个方法中以供重用:

impl SomeEnum {
    fn as_trait(&self) -> &SomeTrait {
        match *self {
            SomeEnum::Value1(ref x) => x,
            SomeEnum::Value2(ref x) => x,
        }
    }
}

fn call_some_func(some_enum: SomeEnum) {
    some_enum.as_trait().some_func();
}

并且可能在枚举本身上实现特征,如果所有变体都实现的话。这样消费者就不用关心了:

impl SomeTrait for SomeEnum {
    fn some_func(&self) {
        self.as_trait().some_func()
    }
}