プリミティブ型について
変数について見ていきたいところですが、変数に指定できるプリミティブ型を先に見てみましょう。
※汎用的な型の表記として "T, U" を使用します。
以下の型はRustにおけるプリミティブなスカラ型になります。
型 | 型名 | 備考 |
---|---|---|
unit |
ユニット型 | 誤解を恐れずに言うと void
|
bool |
論理値型 | true, false |
i8 |
8bit符号付き整数型 | |
u8 |
8bit符号なし整数型 | |
i16 |
16bit符号付き整数型 | |
u16 |
16bit符号なし整数型 | |
i32 |
32bit符号付き整数型 | 型推論でのデフォルト |
u32 |
32bit符号なし整数型 | |
i64 |
64bit符号付き整数型 | |
u64 |
64bit符号なし整数型 | |
i128 |
128bit符号付き整数型 | |
u128 |
128bit符号なし整数型 | |
isize |
符号付き整数型 | CPUのメモリアドレスのビット幅に依存 |
usize |
符号なし整数型 | CPUのメモリアドレスのビット幅に依存 |
f32 |
32bit浮動小数点型 | |
f64 |
64bit浮動小数点型 | 型推論でのデフォルト |
char |
文字型 | |
&T, &mut T |
参照型 | |
*const T, *mut T |
生ポインタ型 | unsafe |
fn(T) -> U |
関数ポインタ型 |
以下の型はRustにおけるプリミティブな複合型になります。
型 | 型名 | 備考 |
---|---|---|
(T, U, ...) |
タプル型 | カンマで区切った要素の組を表す |
[T; size] |
配列型 | sizeには数字を入れ、コンパイル時の固定長 |
&[T], &mut[T], Box<[T]> |
スライス型 | 長さは実行時決定 |
&str |
文字列スライス型 |
変数について
Rustでは変数周りに特徴的な仕組みが多く使われています。
変数の定義自体について詳しく見ていきたいと思います。
// 基本の構文
let 変数[: T] [= 初期化式];
let文 を用いることで変数の定義が行なえます。
Rustでは変数と値を結びつけることを 「束縛する」 と言います。
よく他言語では代入と言ったりしますが、Rustではそうは言いません。
Rustでは初期化式は省略しても変数の定義は可能ですが、できるだけ避けるべきです。
なぜなら、値のない状態の変数を使用することはできないからです。
コンパイル時にエラーになります。
忘れないためにも、何らかの理由で初期化できない場合を除いて、初期化は変数の定義時に行なっておくほうが良いでしょう。
ミュータビリティについて
let文 で定義した変数はデフォルトでイミュータブル(変更不可)になります。
Rustは変数の値の変更についてかなり厳格である証拠だと思います。
他言語では逆にデフォルトでミュータブル(変更可能)なものが多いですね。
ミュータブルな変数を定義するには以下のように書きます。
// 基本の構文
let mut 変数[: T] [= 初期化式];
これで他の言語と同様にコード内で値の変更を行うことができます。
とは言え、Rust的な思想として必要な変数以外はミュータブルにすべきではないと思います。
スコープについて
変数のスコープについては { }
(ブロック)内でのみ有効です。
fn scope_example() {
let x = 10;
if x == 10 {
let y = 20;
println!("{}", y);
}
{
let z = 30;
// println!("{}", y); <= エラーになる
println!("{}", z);
}
println!("{}", x);
// println!("{}", y); <= エラーになる
// println!("{}", z); <= エラーになる
}
コメントで「エラーになる」とある部分は全てスコープ外のため、変数の値がない状態になっているので参照できません。
シャドウイングについて
変数は同じ名前で複数作成することができます。
fn shadowing_example() {
let x = 10; // xを定義
let x = 20; // 新しいxを定義
let x = "hoge" // 新しい変数を定義して値に束縛するので、変数の型が変わっても問題ない
println!("{}", x); // xは"hoge"
{
let x = 30; // ブロック内のみで有効なx
println!("{}", x); // xは30
}
println!("{}", x); // xは"hoge"
}
一時利用の変数に関して、変な名前をつけなくて良いという利点があります。
ただし、ブロック内で変数名が被ってしまうと再定義されて予期しないことになるので、そこはしっかりと意識しなければなりません。
シャドウイングは一度定義した変数の束縛先を変更するものではなく、新しい変数の定義なので、変数のミュータビリティとは別の話です。
定数とスタティック変数
const文 を用いることで定数も定義できます。
定数は一度値が定義されると、値の変更はできません。
また、シャドウイングのようなこともできません。
// 基本の構文
const 名前: T = 定数式;
static文 を用いることで、グローバルスコープで利用可能なスタティック変数の定義ができます。
// 基本の構文
static [mut] 名前: T = 定義式;
定数はコンパイル時に一度だけ計算され値が埋め込まれます。
他方、スタティック変数は参照のたびに計算が行われます。
そのため、ミュータブルにすることも可能です。
ミュータブルなスタティック変数の読み書きには unsafe
な環境下で行う必要があります。
const TEST: i32 = 10;
static mut GLOBAL_FLAG: bool = false;
fn main() {
println!("{}", TEST); // 10
unsafe {
println!("{}", GLOBAL_FLAG); // false
GLOBAL_FLAG = true;
println!("{}", GLOBAL_FLAG); // true
}
}
unsafe
については別途説明予定です。
最後に
変数の定義関連について見てみました。
基礎的な部分は忘れがちですが、しっかりと覚えておくべきです。
参照文献