Chapter 05

変数と型

対応する APG4b の箇所:1.04.変数と型

変数

プログラム内では,変数を使用することができます. APG4b の表現にならうと,変数は「メモ」のようなものです.値に名前を付け,メモとして覚えておいて,後で使うことができます.

まず,次のようなコードを用いて変数について説明します.

fn main() {
    let hoge; // 宣言
    hoge = 10; // 代入
    println!("{} {} {}", hoge, hoge + 2, hoge * 2); // 使用
}

hoge という名前の変数が使われています.

ここでは変数に hoge という名前を付けましたが, abcxxx などでもかまいません.例として用いられる特に意味の無い名前 hogeメタ構文変数といいます.

宣言

変数を使うには,まず宣言をする必要があります.

let hoge;

hoge という名前の変数を宣言しています.上のたとえで言うなら,何も書かれていない空のメモが存在して, hoge という名前だけが付けられている状態です.

代入

hoge = 10;

と書くと, hoge という名前のメモに, 10 という値が書き込まれます.このことを,「hoge に 10 を代入する」といいます.

変数には一度だけ値を代入することができます.二度以上の代入,すなわち

hoge = 10;
hoge = 20;

のように書くことはできません.

使用

メモに書かれた値は,式の中で使用することができます.

println!("{} {} {}", hoge, hoge + 2, hoge * 2);

では, hoge を 3 回使っています. hoge に 10 という値が代入されていれば,出力は 10 12 20 となります.

数学では x \times 22x とも書きますが,コードの中で x * 22 xx 2 などと書くことはできません.

変数名

変数名のルール

変数名には, a から z までの小文字アルファベット, A から Z までの大文字アルファベット, 0 から 9 までの数字,そしてアンダースコア _ が使えます.たとえば, hogeexpo2025very_long_name などが変数名として使えます.

ただし,次のような名前は使えません.

  • 551horai のように,先頭が数字であるようなものは変数名として使えません.
  • 単独のアンダースコア _ は特別な意味をもつため,普通の変数名としては使えません. _x__ (アンダースコア 2 つ)であれば使えます.
  • crate self super Self の 4 つは変数名として使えません.
  • fnlet など,いくつかの名前はキーワードとして予約されており,変数名として使えません.どうしても使いたい場合は,先頭に r# を付けて r#fn とする必要があります.
    キーワードの一覧はここにあります.

慣例

今後,変数以外に名前を付けるときにも,上と同じルールが登場することがあります.たとえば定数や構造体などです.ルールを満たしていればどんな名前を付けてもエラーにはならないのですが,変数と定数を区別するなどの目的で,変数名の付け方には以下のような慣例が定められています.

先頭は大文字にしない

変数に名前を付けるとき,先頭に大文字アルファベットは使用しません.一方,定数や構造体に付ける名前は先頭を大文字にします.

スネークケースにする

たとえば,"max height"(高さの最大値)を表す変数に対して名前を付けるときは, max と height をアンダースコア _ でつないで max_height とします.このように,複数の単語を _ でつないで変数名にするやり方をスネークケースといいます.一方,構造体などに名前を付ける際には MaxHeight のように大文字と小文字を使って単語の区切りを表します.これをキャメルケースといいます.

使用しない変数は _ で始める

代入しただけで使わない変数がある場合は,名前を _ から始めます.

変数の値は,内部的に 0 と 1 の並び(ビット列)で表されます.

たとえば,整数 10 は 2 進法で 1010 なので,コンピュータのメモリ上では 00000000 00000000 00000000 00001010 のように表されます.

一方,小数の 2.5 は(単精度浮動小数点数の場合) 0 10000000 01000000000000000000000 のように表されます.これを 2 進法の整数として解釈すると, 1075838976 になってしまいます.

つまり,上のメモのイメージで,実際に書き込まれるのは 0 と 1 の並びでしかないため,解釈の仕方が分からないとメモを読むときに困るわけです.

よって,変数は,ビット列で表された値の他に,「そのビット列をどう解釈すべきか」という情報も持っています.これをといいます.

型注釈

変数の宣言において

let hoge: i32;

と書くと,変数 hogei32 という型になります.このように変数の宣言において型を明記することを,型注釈といいます.たとえば次のような型があります.

ビット数 説明
i32 32ビット 整数を扱うことができる.
f64 64ビット 小数も扱うことができる.
bool 8ビット true / false の 2 つのみを扱うことができる.

他にはこのような型があります.

代入

異なる型の間で代入や計算を行おうとすると,エラーになります.たとえば,

fn main() {
    let hoge: f64;
    hoge = 2;
}

というコードは

error[E0308]: mismatched types
 --> src/main.rs:3:12
  |
3 |     hoge = 2;
  |            ^
  |            |
  |            expected `f64`, found integer
  |            help: use a float literal: `2.0`

というエラーになります.expected `f64`, found integer は「hogef64 型なので, = の右辺にも f64 型の値が来るはずだったが,実際には整数値があった」という意味です. use a float literal: `2.0`は「整数値リテラル 2 の代わりに浮動小数点数リテラル2.0 を使ってはどうか」という意味です.実際, 22.0 に書き換えることで,このコードは正しく動くようになります.

型推論

最初の例に戻ってみましょう.

fn main() {
    let hoge;
    hoge = 10;
    println!("{} {} {}", hoge, hoge + 2, hoge * 2);
}

コード中に hoge の型が書かれていません.では hoge の型は何でしょうか.

実は, hoge の型を明示的に書かなくても,次の hoge = 10; という文から hoge の型が推測されるようになっています.これを型推論といいます.今回は整数値の 10 を代入しているので, hogei32 型であればよいと判断されます.

ではこんなコードを書いたらどうなるでしょうか.

fn main() {
    let hoge;
}

型注釈が無く,その後に hoge の型を推論する材料もないため,型推論ができずエラーになります.

error[E0282]: type annotations needed
 --> src/main.rs:2:9
  |
2 |     let hoge;
  |         ^^^^ consider giving `hoge` a type

type annotations needed は「型注釈が必要である」という意味です. consider giving `hoge` a typeは「変数 hoge に型を与えてみてはどうか」という提案です.

宣言と代入

宣言と代入は同時に行うことができます.

let hoge = 10;

と書くと, hoge という変数が宣言されるとともに, hoge10 が代入されます.型注釈をする場合は

let hoge: i32 = 10;

となります.

未初期化の変数

次のコードを見てみましょう.

fn main() {
    let hoge: i32;
    println!("{}", hoge);
}

hoge に一度も値を代入しないまま, println! マクロの中で使用しようとしています.なんと出力されるでしょうか?分かりません.

このように,一度も値が代入されていない変数は,未初期化であるといいます.未初期化の変数を使おうとするとエラーになります.

error[E0381]: borrow of possibly-uninitialized variable: `hoge`
 --> src/main.rs:3:20
  |
3 |     println!("{}", hoge);
  |                    ^^^^ use of possibly-uninitialized `hoge`

possibly-uninitialized variable というのが「未初期化である可能性のある変数」という意味です.