👻

Rustのenumは合併型にもなる

2024/03/12に公開


Cの共用体まで言わない、TypeScriptの合併型のような事をRustでどう実現すればいいのかを初心者が調べたり考えたりしていました。知っていたはずのenumでした。

やりたかったこと

enum IntOrBool {
    Int(i32, i32),
    Bool(bool),
}
struct Foo {
    func_vec: Vec<fn(IntOrBool) -> IntOrBool>, //ここ4パターンも書きたくなかった
}

fn main() {
    let mut foo = Foo {
        func_vec: Vec::new(),
    };
    foo.func_vec.push(bar as fn(IntOrBool) -> IntOrBool);
    foo.func_vec.push(baz as fn(IntOrBool) -> IntOrBool);
}

fn bar(qux: IntOrBool) -> IntOrBool {
    meaningless_func(qux)
}

fn baz(qux: IntOrBool) -> IntOrBool {
    meaningless_func(qux)
}

fn meaningless_func(qux: IntOrBool) -> IntOrBool {
    match qux {
        IntOrBool::Int(x, _) => {
            println!("It's i32 type!");
            if x < 10 { IntOrBool::Bool(true) } else { IntOrBool::Int(1, 2) }
        },
        IntOrBool::Bool(x) => {
            println!("It's bool type!");
            if x { IntOrBool::Int(3, 4) } else { IntOrBool::Bool(true) }
        },
    }
}

所感

複数の「値」を網羅的に取り扱えるとだけ理解していましたが、複数の「型」としても取り扱えることに気づけました。 普通に共用体のようにも使えますし、Rustのenumの表現力はすごいですね。traitと併せて使うと相当強力なツールになりそうです。オーバーロード的なこともできるなぁと思いましたが、あまり乱用しない方が良さそうです。ちなみにRustにも本当の共用体unionはあるそうです。

参考文献

Discussion