Tommy's Blog

Rustにおけるユーザー定義型

こんにちは。Rustに入門しました(難しい)。今回はユーザー定義型についてです。

型とは

型とは「とりうる値の集合 + 集合の要素に対する演算」です。例えばCのintは以下のようになります。

集合: {..., -1, 0, 1, ...}
演算: +, -など

型は言語にあらかじめ組み込まれている型とユーザーが自分で定義する型に分かれます。
Rustでは型を自分で定義する方法として、構造体と列挙型があります。

構造体

以下ではStudentという構造体を定義しています。これはStudentという型を定義したといえます。なぜなら以下のような集合を定めているからです。

struct Student {
  name: String,
  age: u8
}
集合: {{"foo", 15}, {"hoge", 30}, ...}

構造体と直積

直積とは

直積の定義は次のとおりです。集合A、Bから要素を一つずつ選んで作ったペアを集めたものです。

2つの集合をA、Bとする。このとき{(a,b)∣a∈A,b∈B}を直積集合と言う。

直積の定義とStudent型の例を見比べると、構造体は直積集合とその集合の名前を定義していることがわかります。

列挙型

以下ではDirectionという列挙型を定義しています。内部では、数値(0, 1, 2...)というように表現されます。これはC言語などと同じです。
なお、North, Southなどを列挙子といいます。

enum Direction {
  North,
  South, 
  East,
  West
}

さて、RustではC言語とは異なり以下のように書くことができます。上記と違う点は、列挙子の横に型があることです。

enum Event {
  KeyDown(u8),
  MouseDown {x: i32, y: i32}
}

以下、

  • 列挙型は直和を定義する
  • 上記の2つの列挙型は一見まったく異なるもののように見えるが、同じように見れる

という点について書きます。

列挙子と直和

「構造体は直積を定義している」と本記事では述べましたが、同じように列挙子は直和を定義しているといえます。

直和の定義は以下のとおりです。A、B間に共通の要素がない時は和集合に一致します。共通の要素がある時は、それらを「別のもの」と考えます。例えば、ex.2では{1, 2, 3, 3, 4}となっていますが、これはあえて書くならば{1, 2, 3_A, 3_B, 4}です。

2つの集合をA, Bとする。このとき、直和集合とはA, Bをそのまま合わせたものである。

ex1. A={1, 2} B={3, 4} のとき、直和集合は{1, 2, 3, 4}
ex.2 A={1, 2, 3} B={3, 4} のとき、直和集合は{1, 2, 3, 3, 4}

列挙型において、

列挙子 = 集合名

とみなします。

例えばWebEventではKeyDown, Clickという集合名が存在し、その実態はそれぞれu8, {x:i32, y: i32}です。このとき、WebEventという列挙型は、

{1, 2, ..., {x: 1, y: 2}, ...}

という集合を定義しているといえます。これは直和であることがわかると思います。

では、Directionにおいてはというと、North, South, East, Westという集合名があります。集合の実態は、例えばNorthの場合0のみが要素である集合とみなせます。すなわち以下の集合を定義しているといえ、これは直和です。

{0, 1, 2, 3}

また、列挙子 = 集合名とみなすと列挙型の書き方はいろいろあるが結局は直和を定義していて、違いはどういう集合を組み合わせるかを明示的に指定しているかいないかだけということがわかると思います。