如果我的类型为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() {}
这失败了:
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,
| ^^^^^^^^^^^
而不是other_cases => other_cases
行,我尝试了这一点,也没有成功:
other_cases => {
let o: MyEnum<String> = other_cases;
o
}
答案 0 :(得分:7)
我会在你的枚举上创建一个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);
}
这类似于现有的map
方法,例如Option::map
。
答案 1 :(得分: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() {
}
但重复所有变种并不适用于其中很多变种。
答案 2 :(得分:3)
有些语言(比如C ++)使用Duck Typing:如果它像鸭子一样嘎嘎叫,它必须是鸭子,因此名称很重要。 Rust没有。
在Rust中,名称只是我们人类的一些显示效用,B
和MyEnum<u32>
中的MyEnum<String>
可能恰好具有相同的视觉表现形式,但它们完全不同于句法就语言而言,实体。
有多种方法可以减轻你的痛苦:
build.rs
脚本我将展示后者:
enum MyEnumImpl {
A,
B,
C,
}
enum MyEnum<T> {
Independent(MyEnumImpl),
Dependent(T),
}
显然,后者使得手动映射事物变得更加容易。
答案 3 :(得分:2)
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)));
}