let / mut / const / static
| 対応: | Rust 1.0(2015) |
|---|
Rustでは『let』で変数を宣言し、デフォルトでは不変(immutable)です。可変にするには『mut』が必要です。『const』と『static』はプログラム全体で有効な定数・静的変数を定義します。
構文
// 不変変数 let 変数名: 型 = 値; let 変数名 = 値; // 型推論を使用します。 // 可変変数 let mut 変数名 = 値; // 定数(型注釈が必須・コンパイル時評価) const 定数名: 型 = 値; // 静的変数(プログラム全体で有効なメモリを持ちます) static 変数名: 型 = 値; // シャドーイング(同名の変数を再宣言します) let 変数名 = 値; let 変数名 = 新しい値; // 前の変数を隠します。
宣言方法一覧
| 宣言 | 可変性 | 概要 |
|---|---|---|
| let x = 値 | 不変 | デフォルトの変数宣言です。再代入はできません。 |
| let mut x = 値 | 可変 | 再代入・変更が可能な変数です。 |
| const NAME: 型 = 値 | 不変 | コンパイル時に評価される定数です。型注釈が必須です。 |
| static NAME: 型 = 値 | 不変 | 固定メモリアドレスを持つ静的変数です。'staticライフタイムを持ちます。 |
| シャドーイング | 不変→不変 | 同名で再宣言して値・型を変えられます。元の変数は隠れます。 |
サンプルコード
変数束縛(『let』)、可変変数(『mut』)、定数(『const』)の使い方を確認するサンプルコードです。
sample_let_mut_const.rs
const MAX_POINTS: u32 = 100_000;
static GREETING: &str = "こんにちは";
fn main() {
// 不変変数
let x = 5;
// x = 6; // エラー:不変変数には再代入できません。
// 可変変数
let mut y = 5;
y = 6; // 再代入できます。
println!("y = {}", y); // 『6』と出力されます。
// 型推論
let z = 3.14; // f64と推論されます。
println!("z = {}", z);
// シャドーイング(型を変えることもできます)
let spaces = " "; // &str型
let spaces = spaces.len(); // usize型(型が変わっています)
println!("spaces = {}", spaces); // 『3』と出力されます。
// シャドーイングで段階的に変換します。
let input = " 42 ";
let input = input.trim(); // 前後の空白を除去します。
let input: i32 = input.parse().unwrap(); // 数値に変換します。
println!("input = {}", input); // 『42』と出力されます。
// スコープ内のシャドーイング(外側の変数には影響しません)
let value = 10;
{
let value = value * 2; // このブロック内でのみ有効です。
println!("inner value = {}", value); // 『20』と出力されます。
}
println!("outer value = {}", value); // 『10』のままです。
// 可変変数をシャドーイングで不変に固定します。
let mut count = 0;
count += 1;
let count = count; // 以降は再代入できません。
println!("MAX: {}", MAX_POINTS);
println!("{}", GREETING);
println!("count: {}", count);
}
コンパイルして実行すると次のように出力されます。
rustc let_mut_const.rs ./let_mut_const y = 6 z = 3.14 spaces = 3 input = 42 inner value = 20 outer value = 10 MAX: 100000 こんにちは count: 1
よくあるミス
よくあるミス1: 不変変数に再代入しようとするコンパイルエラー
Rustの変数はデフォルトで不変(immutable)です。再代入するには『mut』が必要です。
fn main() {
let x = 5;
// コンパイルエラー: 不変変数には再代入できない
// x = 6; // error: cannot assign twice to immutable variable `x`
// OK: mut を付けて可変にする
let mut y = 5;
y = 6; // 再代入できる
println!("y = {}", y); // 6
}
よくあるミス2: const と static の使い分けミス
const はコンパイル時に値に置き換えられ、固定メモリアドレスを持ちません。static はメモリ上の固定アドレスを持ちます。可変な静的変数(static mut)はunsafeが必要です。
// const: コンパイル時評価、型注釈必須
const MAX_SIZE: usize = 1024;
// static: プログラム全体で有効な固定アドレスを持つ
static GREETING: &str = "こんにちは";
fn main() {
println!("MAX_SIZE: {}", MAX_SIZE);
println!("{}", GREETING);
// const はインライン展開されるため、アドレスが異なる可能性がある
let a = &MAX_SIZE as *const usize;
let b = &MAX_SIZE as *const usize;
println!("アドレスが同じとは限らない: {}", a == b); // false の可能性
// static は常に同じアドレス
let c = &GREETING as *const &str;
let d = &GREETING as *const &str;
println!("アドレスは同じ: {}", c == d); // true
}
よくあるミス3: シャドーイングと可変変数の混同
シャドーイング(let x = 新しい値)は新しい変数を作ります。元の変数の型も変えられます。一方、mut による再代入は同じ変数の値を変えるだけで型は変えられません。
fn main() {
// シャドーイング: &str 型を usize 型に変換できる
let value = "42"; // &str
let value = value.parse::<usize>().unwrap(); // usize(別の変数)
println!("value: {}", value); // 42
// mut 再代入: 型は変えられない
let mut count = 0i32;
count = 10; // OK: 同じ i32 型
// count = "hello"; // コンパイルエラー: 型が違う
println!("count: {}", count); // 10
}
概要
Rustでは変数がデフォルトで不変であるため、意図しない変更を防げます。可変性が本当に必要な場合にのみ『mut』を使うことで、コードの意図が明確になります。
シャドーイングは『mut』とは異なり、型の変換やスコープ内での再利用に便利です。例えば、文字列の入力を段階的にトリム→数値変換するような場面では、各段階で別名の変数を用意する必要がありません。また、ブロックスコープ内でシャドーイングした変数は外側に影響しないため、一時的な計算にも安全に使えます。ただし『mut』変数のシャドーイングで可変性を失わせるパターンは、意図を明示的にコメントで残しておくのが一般的です。
数値リテラルにはアンダースコア(_)を区切り文字として使えます(例:『100_000』)。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。