型ってなに?
まずは公式サイトを確認する。
Every value in Rust is of a certain data type, which tells Rust what kind of data is being specified so it knows how to work with that data.
直訳すると
「Rustにおけるすべての値はあるデータ型であり、それによりRustは、そのデータの種類が何なのか特定し、どのように動作するのか明らかにしている」
これは仕様を説明しているだけで、型の定義とはちょっと言い難い。
というわけで、本やらネットやらを漁って自分なりに定義してみた。
定義:Rustにおける型とは
同じメモリ構造(サイズ、配置、解釈)と演算を持つデータの集合を"型"と呼ぶ。
ここでの演算とは、+とか×といった四則演算だけでなく、データをコピーする、書き換えるといったあらゆる振る舞いを含む。演算は複数持つことも、全く持たないこともできる。
具体例
一番馴染みがある数値型を例にする。
fn main() {
let a = 10; // コンパイラに型を推論させる
let b: i64 = 20; // 符号付き整数型
let c: u64 = 20; // 符号なし整数型(自然数)
let d: f64 = 3.14159265 // 浮動小数点型(実数)
}
上記の変数b, c, dは同じ64ビットだが、
i64は先頭1ビットが符号、以降の63ビットで自然数を表す
u64は64ビットすべてで自然数を表す(つまりi64よりも大きな自然数を格納できる)
f64は先頭1ビットが符号、そこから指数部が11ビット、仮数部が52ビット
といった具合にメモリの解釈が異なる。
演算については、上記のいずれも加法、乗法といった一般的な四則演算をサポートしている。それ以外にも「比較」や「剰余」だったり、「型変換」なども持っている。他にも、値を変数に代入するとき、コピーするのか、所有権をmoveするのか、なども演算としてすべて定義されている。
このように、メモリ構造×演算の組み合わせが型である。
これ以外にもRustには「配列型」「スライス型」「ベクター型」など色々あるが、メモリ構造×演算という原則は変わらない。
また、「struct」や「enum」で型を自作することもできる。
struct、enumで作った型はデフォルトでは演算をもっていない(メモリ構造の定義のみ)。
もちろんそのまま使用しても問題ないが、「impl」、「trait」を使って演算すらも自作して、より自由で柔軟な型を作り上げることもできる。