Rustを書き始めて、かなり早い段階で出てくる疑問があります。
-
i32とi64は何が違うのか -
usizeはいつ使うのか - なんとなく
i64を使っていないか
今回は、Rustにおける数値型の 32 / 64 の違いを、
実装者目線で整理します。
Rustの数値型は「サイズが明示的」
Rustでは、数値型のサイズがすべて明示的です。
let a: i32 = 10;
let b: i64 = 10;
この2つは見た目が似ていますが、
メモリサイズも用途も別物です。
i32 と i64 の基本的な違い
ビット幅と表現できる範囲
-
i32- 32bit 符号付き整数
- 約 -21億 〜 +21億
-
i64- 64bit 符号付き整数
- 約 -922京 〜 +922京
単純に言えば、
- 扱える数値の大きさが違う
- メモリ使用量も違う
という差があります。
なぜRustではi32がデフォルトなのか
Rustでは、整数リテラルのデフォルトは i32 です。
let x = 10; // i32
理由は明確です。
- 多くの用途で 32bit で十分
- CPU的に扱いやすい
- メモリ効率が良い
- キャッシュ効率が良い
つまり、
- 「とりあえず使う整数」=
i32
という設計思想です。
なんとなくi64を使うのが危険な理由
Rust初心者にありがちなのが、
let x: i64 = 0;
という なんとなくi64 です。
問題点は以下です。
- 本当に64bitが必要か考えていない
- API境界で型変換が増える
- 他のライブラリと噛み合わない
特に、
- ループカウンタ
- 配列インデックス
- サイズ計算
などで i64 を使うと、
usize との変換地獄にハマります。
usize と 32 / 64 の関係
usize は少し特殊です。
- 実行環境のポインタサイズに依存
- 64bit OS →
usize = 64bit - 32bit OS →
usize = 32bit
主な用途は、
- 配列インデックス
- メモリサイズ
- バッファ長
です。
let v = vec![1, 2, 3];
let len: usize = v.len();
ここで i32 や i64 を使うと、
型変換が必ず必要になります。
パフォーマンスへの影響
現代のCPUでは、
- 32bit と 64bit の演算速度はほぼ同じ
ですが、違いが出るのは メモリ周り です。
- 構造体が大きくなる
- キャッシュ効率が下がる
- メモリアクセスが増える
大量データを扱う場合、
i64の使いすぎは確実に効いてきます。
どちらを選ぶべきかの指針
迷ったら、以下で考えると安全です。
- 値の上限が 21億以内 →
i32 - 本当に巨大な数値が必要 →
i64 - インデックス・サイズ →
usize - 外部仕様で決まっている → それに合わせる
Rustでは、
- 型は「意思表示」
です。
型が厳しいのはRustの設計思想
Rustが数値型を細かく分けている理由は、
- 曖昧さを排除する
- 意図しない変換を防ぐ
- バグを未然に潰す
ためです。
最初は面倒に感じますが、
- 型が決まる
- 設計が決まる
- 実装が安定する
という流れを、一度体験すると戻れません。
まとめ
-
i32とi64は用途が違う - Rustでは
i32がデフォルト - なんとなく
i64は危険 -
usizeはインデックス用 - 型は設計の一部
Rustの数値型は、
「制約」ではなく 道具 です。
正しく使い分けると、
コードの意図が驚くほどクリアになります。