如何将参数化枚举从泛型类型映射到另一个类型?

dar*_*que 6 rust

如果我有类型的类型MyEnum<T>,如果不是每个变量都参数化,我怎么能映射它?

例如,我想转换MyEnum<u32>MyEnum<String>:

enum MyEnum<T> {
    B,
    C,
    D(T),
}

fn trans(a: MyEnum<u32>) -> MyEnum<String> {
    match a {
        MyEnum::D(i) => MyEnum::D(i.to_string()),
        other_cases => other_cases,
    }
}

fn main() {}
Run Code Online (Sandbox Code Playgroud)

这失败了:

error[E0308]: match arms have incompatible types
  --> src/main.rs:8:9
   |
8  |         match a {
   |         ^ expected struct `std::string::String`, found u32
   |
   = note: expected type `MyEnum<std::string::String>`
   = note:    found type `MyEnum<u32>`
note: match arm with an incompatible type
  --> src/main.rs:10:28
   |
10 |             other_cases => other_cases,
   |                            ^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

取而代之的是的other_cases => other_cases路线,我想这一点,也没有成功:

other_cases => {
    let o: MyEnum<String> = other_cases;
    o
}
Run Code Online (Sandbox Code Playgroud)

She*_*ter 8

我会map在你的枚举上创建一个方法:

#[derive(Debug)]
enum MyEnum<T> {
    B,
    C,
    D(T),
}

impl<T> MyEnum<T> {
    fn map<F, U>(self, f: F) -> MyEnum<U>
    where
        F: FnOnce(T) -> U,
    {
        use MyEnum::*;

        match self {
            B => B,
            C => C,
            D(x) => D(f(x)),
        }
    }
}

fn main() {
    let answer = MyEnum::D(42);
    let answer2 = answer.map(|x| x.to_string());
    println!("{:?}", answer2);
}
Run Code Online (Sandbox Code Playgroud)

这类似于现有map方法,例如Option::map.


dar*_*que 5

嗯,这实际上是一个答案:

enum MyEnum<T> {
    B,
    C,
    D(T),
}

fn trans(a: MyEnum<u32>) -> MyEnum<String> {
    match a {
        MyEnum::D(i) => MyEnum::D(i.to_string()),
        MyEnum::B => MyEnum::B,
        MyEnum::C => MyEnum::C
    }
}

fn main() {
}
Run Code Online (Sandbox Code Playgroud)

但重复所有变种是不可接受的,当它们有很多时......

  • 这正是您需要做的。对于大型案例,您可能能够形成一个有帮助的宏。 (2认同)

not*_*dle 3

macro_rules! partial_enum {
    ($name: ident, $some: ident, $($none: ident),+) => {
        #[derive(Debug)]
        enum $name<T> {
            $some(T),
            $($none),+
        }
        impl<T> $name<T> {
            fn convert<U>(self) -> Result<$name<U>, T> {
                match self {
                    $name::$some(x) => Err(x),
                    $($name::$none => Ok($name::$none)),+
                }
            }
        }
    }
}
partial_enum!(MyEnum, D, B, C);
fn trans(a: MyEnum<u32>) -> MyEnum<String> {
    let a_split: Result<MyEnum<String>, u32> = a.convert();
    match a_split {
        Ok(is_none) => is_none,
        Err(not_none) => MyEnum::D(not_none.to_string()),
    }
}
fn main() {
    println!("{:?}", trans(MyEnum::D(13)));
}
Run Code Online (Sandbox Code Playgroud)