この記事ではRustの変数について、プログラミング初心者の方でもバッチリわかるように解説していきます!
Rustを学び始めたばかりだと、「変数ってどうやって作るの?」「なんで変更できないの?」「`mut`って何?」なんて疑問が次々に出てきますよね。
この記事を読めば、Rustの変数の基本から、ちょっと応用的な使い方、そして気をつけるべき点まで、一通りマスターできます。
この記事で学べること
- Rustの変数の基本的な考え方
- 変数の作り方(`let`と`mut`の違い)
- 変数の「型」ってなんだろう?(型推論と型指定)
- 実際のコードでの変数の使い方
- 変数が使える範囲「スコープ」の話
- Rustならではの「シャドーイング」とは?
- 変数を使うときに注意したいポイント
Rustの変数とは?
プログラミングの世界で「変数」というと、データを一時的に入れておくための「箱」みたいなものだと考えてみてください。
計算結果や、ユーザーが入力した文字など、後で使いたい情報をしまっておく場所ですね。
Rustにももちろん変数があります。
ただ、Rustの変数は、プログラムが安全に、そして速く動くように、ちょっとしたルールが設けられているんです。他の言語から来た人は、最初は少し戸惑うかもしれませんが、慣れるととても合理的だと感じるはずですよ。
Rustでの変数の宣言方法 - `let`キーワードが基本
Rustで変数を作るには、let
というキーワードを使います。
宣言する、なんて言うと難しく聞こえますが、要は「こういう名前の箱を用意しますよ」とコンピューターに教えてあげる感じです。
書き方はこんな感じ。
let x = 5; let message = "こんにちは";
let
の後に変数名(ここではx
とかmessage
)、そして=
を書いて、入れたい値(データ)を書きます。最後にセミコロン;
を忘れずに。
ここでRustの面白い特徴!let
だけで作った変数は、基本的に後から中身を変えられません。
これを「イミュータブル(immutable)」、つまり不変である、と言います。安全第一なRustらしい考え方ですね。
イミュータブル(不変)な変数とは?
先ほど説明した通り、let
だけで作った変数は、一度値を入れると、後から別の値を入れなおすことはできません。
「え、変更できないの不便じゃない?」と思うかもしれませんが、プログラムが意図しないところで値が変わってしまうミスを防げる、という大きなメリットがあるんです。
例えば、こんなコードを書くとエラーになります。
fn main() { let x = 5; println!("xの値は: {}", x); // ↓ここでエラー!イミュータブルな変数xに再代入しようとしている // x = 6; // println!("xの値は: {}", x); }
上のコードのコメントアウト(//
)を外して実行しようとすると、コンパイラ(プログラムをコンピューターがわかる言葉に翻訳するやつ)が「cannot assign twice to immutable variable `x`
」みたいな感じで怒ってきます。
「不変の変数xには二度も代入できませんよ!」ということですね。
このように、Rustはプログラムを実行する前に、ルール違反がないか厳しくチェックしてくれるので、安心して開発が進められます。
ミュータブル(可変)な変数 - `mut`キーワード
「でも、どうしても途中で値を変えたい時もあるんだけど…」もちろん、そういう場面もありますよね。
ご安心を!値を変えられるようにしたい場合は、let
の後ろにmut
(ミュータブル、mutableの略)を付け加えます。
こんな風に書きます。
fn main() { let mut y = 10; // mut を付けて宣言 println!("最初のyの値は: {}", y); y = 20; // mut が付いているので再代入OK! println!("新しいyの値は: {}", y); }
これを実行すると、ちゃんとyの値が10から20に変わります。
最初のyの値は: 10 新しいyの値は: 20
mut
を付けることで、「この変数は後で値が変わる可能性があるよ」と、プログラムを読む人にも、コンパイラにも、はっきりと意思表示するわけです。
変更する可能性がある変数にだけmut
を付ける、これがRust流の安全な書き方です。
Rustの変数の型 - 型推論と型注釈
Rustは「静的型付け言語」と呼ばれます。
これは、変数に入れるデータの種類(数値なのか、文字なのか、など)を、プログラムを実行する前にはっきりさせる必要がある、という意味です。このデータの種類のことを「型(かた)」と呼びます。
でも、毎回「これは数値の型ですよ」「これは文字列の型ですよ」と書くのは少し面倒ですよね?
そこでRustには「型推論(かたすいろん)」という賢い機能があります。
多くの場合、変数に入れる値から、コンパイラが「ふむふむ、この変数には整数が入ってるから、これは整数型だな」と自動で型を判断してくれるんです。
fn main() { let num = 10; // コンパイラが「これは整数型(i32)だな」と推論 let pi = 3.14; // コンパイラが「これは小数型(f64)だな」と推論 let is_rust_fun = true; // コンパイラが「これは真偽値型(bool)だな」と推論 println!("num: {}", num); println!("pi: {}", pi); println!("is_rust_fun: {}", is_rust_fun); }
ただ、場合によってはコンパイラが型を判断できなかったり、プログラマが特定の型を明示したい時もあります。
そういう時は、「型注釈(かたちゅうしゃく)」を使って、自分で型を指定できます。変数名の後にコロン:
と型名を書くだけです。
fn main() { let guess: u32 = "42".parse().expect("数字ではありません!"); // 文字列を数値に変換。型注釈が必要な例 let big_number: i64 = 100_000_000; // i64型(大きな整数)を明示 println!("guess: {}", guess); println!("big_number: {}", big_number); }
よく使う基本的な型には、以下のようなものがあります。
- 整数型
i32
(符号付き32ビット整数、よく使われる),u32
(符号なし32ビット整数),i64
など - 浮動小数点数型
f64
(倍精度浮動小数点数、よく使われる),f32
- 論理値型
bool
(true
またはfalse
) - 文字型
char
(1文字、例えば 'a' や '亜') - 文字列スライス型
&str
(文字列の一部または全体を参照、例えば "hello")
最初は型推論に任せつつ、必要に応じて型注釈を使う、という感じで慣れていくと良いでしょう。
Rustの変数の使い方 - サンプルプログラムで実践
さて、これまで学んだlet
、mut
、そして型を使って、実際に変数がプログラムの中でどう活躍するのか見てみましょう!
簡単なサンプルプログラムを用意しました。ユーザーに年齢を尋ねて、数年後の年齢を表示する、というものです。
use std::io; // 入出力ライブラリを使う宣言 fn main() { println!("こんにちは!あなたの年齢を教えてください。"); let mut age_input = String::new(); // 入力を受け取るための空の文字列変数 (mutが必要) io::stdin() .read_line(&mut age_input) // ユーザーからの入力を読み込む .expect("入力の読み込みに失敗しました"); // 入力された文字列を数値(u32型)に変換。型注釈とエラー処理が必要 let age: u32 = age_input.trim().parse() .expect("数字を入力してください"); println!("なるほど、あなたは {} 歳なのですね!", age); let after_years = 5; // 5年後を計算するための変数 (イミュータブル) let future_age = age + after_years; // 年齢計算 println!("{} 年後、あなたは {} 歳になりますね。", after_years, future_age); }
このプログラムでは、let mut age_input
でユーザー入力を受け取るための「可変な」文字列変数を用意し、let age: u32 = ...
で入力された文字列を「不変な」数値変数に変換しています。
そして、let after_years
とlet future_age
という「不変な」変数を使って計算結果を保持していますね。
サンプルプログラムの実行結果と解説
上記のプログラムを実行すると、まず年齢を聞かれます。例えば「25」と入力してみましょう。
こんにちは!あなたの年齢を教えてください。 25 (← ユーザーが入力) なるほど、あなたは 25 歳なのですね! 5 年後、あなたは 30 歳になりますね。
ちゃんと入力した年齢が表示され、5年後の年齢が計算されて表示されましたね!
ポイントは、age_input
は最初空っぽで、ユーザーの入力によって中身が変わる必要があったのでmut
が必要でした。一方、変換後のage
や計算に使うafter_years
、結果のfuture_age
は一度決まったら変わらないのでmut
は不要(むしろ付けない方が安全)ということです。
このように、変数の役割に応じてmut
を適切に使い分けることが、Rustプログラミングのコツの一つです。
変数のスコープ - 変数が有効な範囲
変数には「スコープ」という考え方があります。
これは、その変数がプログラムのどの範囲で有効か、つまり使える範囲のことです。難しく考えず、変数の「縄張り」みたいなものだと思ってください。
Rustでは、変数のスコープは基本的に、その変数が宣言された波カッコ{}
で囲まれたブロック内になります。
fn main() { let x = 10; // このxはmain関数の最後まで有効 { // ここから新しいスコープ(ブロック)が始まる let y = 5; // このyはこのブロックの中だけで有効 println!("ブロック内のx: {}, y: {}", x, y); // xもyも使える } // ここでyのスコープは終わり println!("ブロック外のx: {}", x); // println!("ブロック外のy: {}", y); // ←これはエラー!yはこのスコープには存在しない }
上の例では、変数y
は内側の波カッコ{}
の中で宣言されているので、そのブロックが終わると使えなくなってしまいます。
最後の行のコメントを外して実行しようとすると、「cannot find value `y` in this scope
」(このスコープにyは見つかりません)というエラーが出ます。
変数はそれが宣言されたスコープの中でしか生きられない、と覚えておきましょう。これにより、関係ない場所で変数が使われてしまうことを防ぎ、プログラムが整理されます。
Rustの変数における重要な概念 - シャドーイング
Rustには「シャドーイング(Shadowing)」という、ちょっと面白い変数の機能があります。
これは、既に存在する変数と同じ名前で、let
を使って新しい変数を宣言することです。そうすると、新しい変数が古い変数を「影で隠す(シャドーイング)」ようにして、そのスコープ内では新しい変数の方が使われるようになります。
言葉だと分かりにくいので、例を見てみましょう。
fn main() { let x = 5; println!("最初のx: {}", x); // 出力: 5 let x = x + 1; // シャドーイング! 新しい変数xを宣言 println!("シャドーイング後のx: {}", x); // 出力: 6 { let x = x * 2; // さらに内側のスコープでシャドーイング println!("内側スコープのx: {}", x); // 出力: 12 } // 内側のスコープ終わり。ここのxは消える println!("スコープを抜けた後のx: {}", x); // 出力: 6 (内側のxではなく、その前のx=6が使われる) // 型を変えることもできる! let spaces = " "; // spacesは文字列スライス型 (&str) let spaces = spaces.len(); // 同じ名前で再宣言!今度は数値型 (usize) println!("スペースの数: {}", spaces); // 出力: 3 }
let x = x + 1;
の部分がシャドーイングです。mut
を使ってx = x + 1;
と書く(再代入)のとは違います。シャドーイングは、あくまでlet
で新しい変数を宣言し直しているのがポイント。
そのため、シャドーイングを使うと、変数の型を変えることもできます(最後のspaces
の例のように)。
変数の値を一時的に加工したい時や、型変換の結果を同じ変数名で扱いたい時などに便利です。ただし、使いすぎるとコードが読みにくくなることもあるので、用法用量を守って使いましょう!
Rustの変数を使う上での注意点
Rustの変数は安全に使えるように色々工夫されていますが、いくつか気をつけておきたい点があります。特に初心者のうちは、以下の点を意識すると良いでしょう。
未初期化変数について
Rustでは、変数を使う前に必ず何らかの値を入れて初期化しておく必要があります。値を入れずに変数を使おうとすると、コンパイラがエラーを出してくれます。
fn main() { let x: i32; // 宣言だけして初期化しない // println!("xの値は: {}", x); // ← エラー!初期化されていない変数xを使おうとしている // error[E0381]: borrow of possibly-uninitialized variable: `x` }
これは、プログラムが予期しないゴミデータ(初期化前のメモリに入っていた値)を使ってしまうのを防ぐための、Rustの安全機能の一つです。「使う前には必ず値を入れる!」と覚えておけばOKです。
他にも、イミュータブルな変数に再代入しようとしていないか、スコープ外の変数を使っていないか、などもコンパイラが親切に教えてくれます。エラーメッセージをよく読むのが上達への近道ですよ!
【まとめ】Rustの変数を使いこなそう
今回はRustの変数について、基本的なところから少しだけ応用まで、一気に見てきましたね。
ポイントを振り返ってみましょう。
- 変数は
let
で作るのが基本で、デフォルトでは変更不可(イミュータブル)。 - 変更したい変数には
let mut
を使う。 - 多くの場合、型はコンパイラが推論してくれるけど、自分で指定(型注釈)もできる。
- 変数には使える範囲(スコープ)がある。
let
で同じ名前の変数を再宣言する「シャドーイング」という機能がある。- 使う前には必ず初期化が必要。
Rustの変数は、最初は少しルールが多いように感じるかもしれません。でも、これらのルールがあるおかげで、私たちはより安全で信頼性の高いプログラムを書くことができるんです。
変数の扱い方に慣れることは、Rustをマスターするための大きな一歩です。ぜひ、この記事のコードを実際に動かしてみて、色々試してみてくださいね。
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。