Rustの変数とデータ型:`let`から型システムまでを網羅したガイド
Rustでは、変数はデフォルトで不変です。これは制限ではなく、安全性を保証するためのものです。
Rustの変数システムと型システムは、メモリの安全性を重視するRustの基盤となっています。不変性、型推論、スカラー型を理解することは、Rustを習得するための第一歩です。
1. 学習内容
letを使用して変数を宣言し、不変性を理解するlet mutを使用して変更可能な変数を作成するconstを使用して、コンパイル時定数を定義します- Rustの4つのスカラー型:整数、浮動小数点数、ブール値、文字
- 型推論と明示的な型注釈
- 可変シャドウイング機構
2. レジ係の実話
(1) 課題:Excelの数値の誤りを修正する
リサは小さな食料品店のレジ係です。毎日仕事が終わると、彼女はExcelを使ってその日の売上を集計しています:
- 価格は(キャンペーンや割引、会員価格などの影響で)常に変動しているため、彼女は手動でセルを更新しなければならない。
- ある時、彼女はうっかり数式が並んだ行を数値で上書きしてしまい、スプレッドシート全体が台無しになってしまった。
- 再び帳簿の照合を行うのに3時間かかった
Rustを学んだ後、彼女はこう述べた。「Excelのセルがデフォルトで編集不可になっていれば、数式を上書きしてしまう心配もなかったのに。」
(2) Rustの変数モデル
fn main() {
let total_sales: f64 = 1280.50; // Immutable by default -- Today's Sales
// total_sales = 1500.00; // ❌ Compilation Error: You cannot modify immutable variables!
let mut daily_changes = 0.0; // Use mut to declare a mutable variable
daily_changes = 150.0; // ✅ Can be modified
daily_changes = daily_changes + 200.0;
const TAX_RATE: f64 = 0.08; // Compile-time constant, Global Fixed
println!("Tax Rate: {}, Today's Accounts Receivable: {}", TAX_RATE, total_sales * (1.0 + TAX_RATE));
}
Rustの哲学は、「変更する必要がないなら、変更しない」というものです。デフォルトで不変であることで、コードの理解が容易になり、意図しない変更によるバグを減らすことができます。
3. 変数の宣言
(1) let:デフォルトでは不変
let x = 5; // Immutable Variable
// x = 10; // ❌ Compilation Error: cannot assign twice to immutable variable
(2) let mut: 可変変数
let mut y = 5; // Mutable Variable
y = 10; // ✅ Can be reassigned
(3) const:コンパイル時の定数
const MAX_POINTS: u32 = 100_000; // The type must be specified.
const PI: f64 = 3.1415926535;
| 特徴 | let |
let mut |
const |
|---|---|---|---|
| 可変性 | 不変 | 可変 | 不変 |
| 実行時に存在する | はい | はい | いいえ(コンパイル時にインライン化される) |
| 型注釈 | 任意 | 任意 | 必須 |
| グローバルスコープ | いいえ | いいえ | はい |
| 式の評価 | 実行時 | 実行時 | コンパイル時の定数 |
4. スカラー型
Rustには、整数、浮動小数点数、ブール値、文字という4つの基本的なスカラー型があります。
graph TB
A[Scalar Types] --> B[Integer: i8/u8/i16/u16/i32/u32/i64/u64/i128/u128]
A --> C[Floating-point: f32/f64]
A --> D[Boolean: bool]
A --> E[Character: char]
(1) 整数型
| 長さ | 符号付き | 符号なし | 範囲 |
|---|---|---|---|
| 8ビット | i8 |
u8 |
-128 ~ 127 / 0 ~ 255 |
| 16ビット | i16 |
u16 |
-32768 ~ 32767 / 0 ~ 65535 |
| 32ビット | i32 |
u32 |
±21億 / 0 ~ 42億 |
| 64ビット | i64 |
u64 |
±9.2 × 10¹⁸ / 0 ~ 1.8 × 10¹⁹ |
| 128ビット | i128 |
u128 |
最大通信距離 |
| アーキテクチャ | isize |
usize |
システムのビット幅と同じ(64ビットシステム = i64/u64) |
デフォルトの整数型は
i32です。これは最高のパフォーマンスを発揮し、ほとんどの用途で十分です。
(2) 浮動小数点型
let a: f32 = 3.14; // 32-bit precision floating-point (Single Precision)
let b: f64 = 3.141592653589793; // 64-bit precision floating-point (Double Precision, Default Type)
デフォルトの浮動小数点型は
f64です。最新の CPU では、f64 と f32 の処理速度はほぼ同じですが、f64 の方が精度が高くなります。
(3) ブール型
let is_ok: bool = true;
let is_not = false;
ブール値は、条件式 if や while などの条件文でよく使用されます。
(4) 文字の種類
let c: char = 'A'; // ASCII Character
let emoji: char = '🦀'; // Unicode Character(4 Byte)
let han: char = 'Rust'; // Unicode character
Rustにおいて、
charは4バイトを占めるUnicodeスカラー値です。これはASCIIではありません!これにより、Rustは国際化をネイティブにサポートしています。
| 種類 | サイズ | 値の範囲 | 代表的な用途 |
|---|---|---|---|
bool |
1バイト | true / false |
条件チェック、フラグ |
char |
4 バイト | Unicode スカラー値 | 1 文字単位の処理 |
f32 |
4バイト | ±3.4×10³⁸(約7桁の精度) | グラフィックス演算、GPUシェーダー |
f64 |
8 バイト | ±1.8×10³⁰⁸(約15桁の精度) | 科学計算(デフォルトの浮動小数点) |
i32 |
4 バイト | ±21億 | 汎用整数(デフォルト) |
u8 |
1 バイト | 0–255 | バイトデータ、RGB 値 |
usize |
arch | システムのビット幅と同じ | 配列のインデックス、コンテナのサイズ |
5. 型推論とアノテーション
(1) ▶ サンプル:型推論 (難易度 ⭐)
// ============================================
// Rust compiler infers types based on assignments
// ============================================
fn main() {
let x = 42; // Inferred as i32 (Default integer type)
let y = 3.14; // Inferred as f64 (Default floating-point type)
let z = true; // Inferred as bool
let c = 'R'; // Inferred as char
// Can use :type to view (Example in This Section, Not a standard method)
println!("The value of x is: {}", x);
println!("The value of y is: {}", y);
}
出力:
x The value is: 42
y The value is: 3.14
コンパイラは文脈に基づいて型を自動的に推論するため、開発者は至る所で型注釈を指定する必要はありません。
(2) ▶ サンプル:明示的な型注釈 (難易度 ⭐)
// ============================================
// Explicitly Specify the Type -- When a specific size or precision is required
// ============================================
fn main() {
let small: u8 = 255; // u8 Maximum value
let big: i64 = 9_223_372_036_854_775_807; // An underscore can be used as a digit separator
let precise: f32 = 3.141592653589793; // f32 May result in loss of precision
let flag: bool = 5 > 3; // The result of a Boolean expression
println!("small: {}, big: {}, precise: {:.10}, flag: {}", small, big, precise, flag);
}
出力:
small: 255, big: 9223372036854775807, precise: 3.1415927410, flag: true
f32の有効桁数は約 7 桁に過ぎないこと、また3.141592653589793は3.1415927410に切り捨てられていることに注意してください。
(3) ▶ サンプル:変数のシャドウイング(難易度 ⭐⭐)
// ============================================
// Shadowing: Overwrite a previous variable with the same name
// ============================================
fn main() {
let x = 5; // First x
let x = x + 1; // Shadowing: Second x, value becomes 6
let x = x * 2; // Shadowing: Third x, value becomes 12
// Shadowing allows for a change in type!
let name = "Rust"; // &str Type
let name = name.len(); // became usize Type!
println!("x value: {}", x);
println!("name length: {}", name);
}
出力:
x value: 12
name length: 4
シャドウイング ≠ 可変性。 シャドウイングは新しい変数(新しいメモリ領域)を作成するのに対し、
mutは同じメモリブロックを変更します。シャドウイングでは同じスコープ内で変数の型を変更できますが、mutではできません。
(4) ▶ サンプル:総合演習—在庫管理ウィジェット(難易度 ⭐⭐⭐)
// ============================================
// Comprehensive Example: Using Variables, Shadowing and Constants in Inventory Management
// Demo let/mut/const/shadowing Practical Applications
// ============================================
const MAX_STOCK: u32 = 10_000;
const DISCOUNT_THRESHOLD: u32 = 500;
fn main() {
let item_name = "Wireless Mouse";
let price: f64 = 49.99;
let mut stock: u32 = 2500;
println!("=== Inventory Management System ===");
println!("Products: {}", item_name);
println!("Unit Price: {:.2} yuan", price);
println!("Inventory: {} items", stock);
stock = stock - 300;
println!("\n--- Shipped Today 300 items ---");
println!("Remaining Inventory: {} items", stock);
let price = price * 0.85;
println!("\n--- Member Discount 15% off ---");
println!("Member Price: {:.2} yuan", price);
let price = format!("{:.2} yuan", price);
println!("Price Tag: {}", price);
let total_value = (stock as f64) * 49.99;
println!("\nTotal Inventory Value: {:.2} yuan", total_value);
if stock > DISCOUNT_THRESHOLD {
println!("Ample inventory (> {}), No need to restock", DISCOUNT_THRESHOLD);
} else {
let needed = MAX_STOCK - stock;
println!("Out of Stock! Suggested Reorder {} items", needed);
}
println!("Maximum Capacity: {} items", MAX_STOCK);
}
出力:
=== Inventory Management System ===
Products: Wireless Mouse
Unit Price: 49.99 yuan
Inventory: 2500 items
--- Shipped Today 300 items ---
Remaining Inventory: 2200 items
--- Member Discount 15% off ---
Member Price: 42.49 yuan
Price Tag: 42.49 yuan
Total Inventory Value: 109978.00 yuan
Ample inventory (> 500), No need to restock
Maximum Capacity: 10000 items
この例では、定数
const、不変変数let、可変変数let mut、および変数のシャドウイング(シャドウイングされる型がf64からStringに変わる場合)を組み合わせており、これらの異なる変数宣言方法が実際のシナリオにおいてどのように連携して機能するかを示しています。
(5) ▶ サンプル:整数のオーバーフローと安全な演算(難易度 ⭐⭐)
// ============================================
// Integer Overflow Behavior: debug mode panic vs release mode wrapping
// ============================================
fn main() {
let max_u8: u8 = 255;
println!("u8 Maximum value: {}", max_u8);
// Safe Computation Method (No panic, Returns overflow result)
let (result, did_overflow) = max_u8.overflowing_add(1);
println!("255 + 1 (overflowing_add): {}, Did overflow?: {}", result, did_overflow);
let checked = max_u8.checked_add(1);
println!("255 + 1 (checked_add): {:?}", checked);
let saturating = max_u8.saturating_add(100);
println!("255 + 100 (saturating_add): {}", saturating);
let wrapping: u8 = max_u8.wrapping_add(1);
println!("255 + 1 (wrapping_add): {}", wrapping);
let neg_i8: i8 = -128;
let (abs_result, overflow) = neg_i8.overflowing_abs();
println!("i8 absolute value of minimum: {}, Did overflow?: {}", abs_result, overflow);
}
出力:
u8 Maximum value: 255
255 + 1 (overflowing_add): 0, Did overflow?: true
255 + 1 (checked_add): None
255 + 100 (saturating_add): 255
255 + 1 (wrapping_add): 0
i8 absolute value of minimum: -128, Did overflow?: true
Rustでは、整数のオーバーフローはデバッグモードではパニックを引き起こしますが、リリースモードではラップアラウンドとなります。オーバーフローの挙動を明示的に制御するには、
checked_*、saturating_*、およびwrapping_*メソッドを使用することを推奨します。
(6) ▶ サンプル:変数のシャドウイングと型変換の実践的な応用(難易度:⭐⭐⭐)
// ============================================
// Practical Examples of Variable Shadowing: String Parsing Chain
// ============================================
fn main() {
let input = "42.5";
println!("Original Input: {} (Type: &str)", input);
let input = input.parse::<f64>();
println!("Analysis Results: {:?}", input);
let input = match input {
Ok(value) => value,
Err(_) => 0.0,
};
println!("After unpacking: {} (Type: f64)", input);
let input = input as i32;
println!("Round to an integer: {} (Type: i32, Truncation of Decimals)", input);
let input = input * 2;
println!("After doubling: {} (Type: i32)", input);
let input = format!("Result: {}", input);
println!("Final Output: {} (Type: String)", input);
let alice_score = "95";
let alice_score = alice_score.parse::<u32>().unwrap_or(0);
let alice_grade = if alice_score >= 90 { "A" } else { "B" };
println!("Alice: Score={}, Level={}", alice_score, alice_grade);
}
出力:
Original Input: 42.5 (Type: &str)
Analysis Results: Ok(42.5)
After unpacking: 42.5 (Type: f64)
Round to an integer: 42 (Type: i32, Truncation of Decimals)
After doubling: 84 (Type: i32)
Final Output: Result: 84 (Type: String)
Alice: Score=95, Level=A
変数のシャドウイングにより、同じスコープ内でデータ型を段階的に変換することが可能になります――
&str→Result<f64>→f64→i32→String――各段階で同じ変数名を使用することで、冗長性のない明確なコードが得られます。
❓ よくある質問
i64ではなくi32なのはなぜですか?let mutの違いは何ですか?mutは(型を変更せずに)同じ変数を変更します。char は 4 バイトを占めるので、文字列はスペースの無駄ではないですか?char の配列ではありません。const と let の違いは何ですか?const はコンパイル時にインライン展開されますが、let は実行時に割り当てられます。📖 まとめ
- Rustの変数はデフォルトで不変です。可変変数を宣言するには
mutを使用してください constコンパイル時定数には型注釈を付け、すべて大文字の命名規則に従わなければならない- 整数型は、符号付き(i)と符号なし(u)に分類されます。デフォルトでは
i32 - デフォルトの浮動小数点形式は
f64です。charは 4 バイトを占有し、Unicode に対応しています。 - Rustのコンパイラは強力な型推論機能を備えていますが、必要に応じて型を明示的に指定することもできます。
- 変数のシャドウイング により、同じ名前の新しい変数が古い変数を上書きすることができ、型を変更することさえ可能です。
📝 練習問題
- 難易度 ⭐:型
u16の変数を宣言し、値 65535 を代入した後、その値を 65536 に変更しようとして、コンパイラのエラーメッセージを確認してください。 - 難易度 ⭐⭐:
let mutを使用して、1 から 5 までの数字の和を計算する変数を宣言し、その結果を出力するプログラムを作成してください。 - 難易度 ⭐⭐⭐:
constの定数をfn main()の外で宣言し、関数内で使用してみてください。次に、letの変数を関数の外で宣言し、コンパイラエラーを確認してみてください。これにより、constのグローバルスコープを理解するのに役立ちます。



