铸造相同底层类型的枚举变体

时间:2017-04-11 19:05:12

标签: casting rust variant

是否有一种简单的方法可以创建enum,只要基础类型匹配,就能提供强制或以其他方式将实例从一个变体转换为另一个变体的能力?

例如,鉴于此枚举:

enum CanConvert {
    Vec1(Vec<String>),
    Vec2(Vec<String>),
    NotVec(i32),
}

我希望能够在Vec1Vec2变体之间轻松转换:

let v1 = CanConvert::Vec1(["one", "two", "three", "uno", "dos", "tres"]
                          .iter()
                          .map(|&s| s.into())
                          .collect());

let v2 = v1 as CanConvert::Vec2;

上面的代码目前给出了错误not a type,因为枚举变体不是(当前)被认为是类型。即使编译了,也不清楚v1 NotVec变体的情况应该如何处理(恐慌?)。

这有效,但它非常冗长,这看起来应该是一个相当普遍的模式:

let v2 = match v1 {
    CanConvert::Vec1(ref underlying) |
    CanConvert::Vec2(ref underlying) => CanConvert::Vec2(underlying.clone()),
    _ => panic!("v1 did not have appropriate underlying type!"),
};

那么在可能的情况下,有一种简单的方法可以在变体之间提供这种简单的类型转换吗?我还没有编写任何自己的Deref强制措施,但这似乎可能就是我在这里寻找的东西。 (以某种习惯derive包裹的强制将是理想的。)

编辑:请注意,就我所知,没有任何安全的方法可以获得具有所需变体类型的原始引用;需要完整克隆,因为引用必然具有错误的变体标记。但是,似乎应该可以通过简单地更改标记来转换原始enum

1 个答案:

答案 0 :(得分:2)

首先,由于&T是不可变引用,Deref 的实现无法更改类型。它只能指向 in (在这种情况下,它可以指向底层的Vec)。

关于转化,ref在这里引入效率低下,因为它会强迫您clone,如果您取得所有权,则可以简单地移动基础向量:

fn to_v2(v: CanConvert) -> CanConvert {
    match v {
        CanConvert::Vec1(u) | CanConvert::Vec2(u) => CanConvert::Vec2(u),
        _ => panic!("Inappropriate type");
    }
}