パッと出てこなかったので。
例えば、位置か速度か力かわからないベクトルがあるとする。すると、Rustならenum
にするだろう。
enum CoordKind { Position{x:f64, y:f64, z:f64}, Velocity{x:f64, y:f64, z:f64}, } let pos = CoordKind::Position{x: 1.0, y: 2.0, z: 3.0}
これをf64
でもf32
でも使いたいとなると、ジェネリクスを使うことになる。
enum CoordKind<T> { Position{x:T, y:T, z:T}, Velocity{x:T, y:T, z:T}, } let pos = CoordKind::Position::<f32>{x: 1.0, y: 2.0, z: 3.0}
このとき、明示的に型指定する場合はCoordKind::<T>::Position
ではなくCoordKind::Position::<T>
になる。これでちょっと驚いた。
これに対しても普通にmatch
やif let
が使える。その際は、普通にrustc
が型推論をするので普通のenum
と同様に使える。
let pos = CoordKind::Position::<f32>{x: 1.0, y: 2.0, z: 3.0} match pos { CoordKind::Position{x, y, z} => println!("{} {} {}", x, y, z), CoordKind::Velocity{x, y, z} => println!("{} {} {}", x, y, z), }
もし必要なら、CoordKind::Position::<T>{x, y, z}
のように書けば良い。
match pos { CoordKind::Position::<f32>{x, y, z} => println!("{} {} {}", x, y, z), CoordKind::Velocity::<f32>{x, y, z} => println!("{} {} {}", x, y, z), }
間違った型を指定すると以下のように教えてくれる。
error[E0308]: mismatched types --> src/main.rs:15:9 | 15 | CoordKind::Velocity::<f64>{x, y, z} => println!("{} {} {}", x, y, z), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected f32, found f64 | = note: expected type `CoordKind<f32>` found type `CoordKind<f64>`
この型指定方法の微妙なところは、以下のようなものを定義するとよくわかる。
enum Foo<T, U> { Hoge{x: T}, Piyo{x: T}, }
これを明示的に型指定する場合、以下のようにする必要がある。
let x = Foo::Hoge::<i32, f64>{x: 42};
しかも、この場合i32
はともかくf64
は推論しようがないので(他の行でx
をFoo::Piyo<i32, f64>
として使うとかしていない限り)明示的に書く必要がある。
これ、やはり以下の方が直感的だったのではないだろうか。
let x = Foo::<i32, f64>::Hoge{x: 42};
まあ、文法規則は直感的かどうかよりも面倒な縛りがたくさんあるのだろうということは想像はつくが。