記事について
次のTour of Rustを用いて学んだ内容のメモになります。
変数
変数の宣言は、let
キーワードを使用する。
値を割り当てるとき、Rustではほとんどの場合で型を推論できる。
推論できない場合は、宣言時に型を明示する必要がある。
Rustの変数の命名規則は、snake_case
を使用する。
fn main() {
// x の型を推論
let x = 13;
println!("{}", x);
// x の型を指定
let x: f64 = 3.14159;
println!("{}", x);
// 宣言の後で初期化(あまり使われません)
let x;
x = 0;
println!("{}", x);
}
シャドウイング
同じ変数名に複数回値を割り当てることを変数のシャドウイングといい、その変数の型が変更され同じ名前で参照できる
変数の変更
Rustは変数の変更にとても配慮しており、変数は次の2つに分類される。
- 可変値:コンパイラが変数のRead・Writeを許可する
- 不変値:コンパイラが変数のReadのみを許可する
可変値はmut
キーワードで示す。
fn main() {
let mut x = 42;
println!("{}", x);
x = 13;
println!("{}", x);
}
基本的な型
- ブール型:
bool
はtrue/falseを表す - 符号なし整数型:
u8
,u32
,u64
,u128
は正の整数を表す - 符号付き整数型:
i8
,i32
,i64
,i128
は正と負の整数を示す - ポインタサイズ整数型:
usize
,isize
はメモリ内のインデックスとサイズを表す - タプル型:
(value, value, ...)
で表し、固定サイズ値の組を渡すために用いる - 配列型:コンパイル時に長さが決まる同じ型の要素のコレクション
- スライス型:実行時に長さが決まる同じ型の要素のコレクkション
- 文字列スライス:
str
は実行時に長さが決まるテキスト
数値型は値の最後に型を付けることで明示的に指定できる。
fn main() {
let x = 12; // デフォルトでは i32
let a = 12u8;
let b = 4.3; // デフォルトでは f64
let c = 4.3f32;
let bv = true;
let t = (13, false);
let sentence = "hello world!";
println!(
"{} {} {} {} {} {} {} {}",
x, a, b, c, bv, t.0, t.1, sentence
);
}
型の変換
Rustでは、同じ数値の型を扱う場合でも型が明示される必要がある。
明示せず、u8
,u32
等を混ぜるとエラーとなる。
数値型の変換は、as
キーワードを用いることで簡単に行える。
fn main() {
let a = 13u8;
let b = 7u32;
let c = a as u32 + b;
println!("{}", c);
let t = true;
println!("{}", t as u8);
}
定数
定数は、変数のように値が使われる場所でコピーされるのではなく、コンパイル時に値が使われる場所の識別子を直接値に置き換える。
定数の命名規則は、SCREAMING_SNAKE_CASE
を使用する。
const PI: f32 = 3.14159;
fn main() {
println!(
"ゼロからアップル {} を作るには、まず宇宙を創造する必要があります。",
PI
);
}
配列
配列は、要素の型がすべて同じ型の固定長コレクションである。
配列の型は[T;N]
で表し、T
は要素の型、N
はコンパイル時に定める固定長である。
要素を扱うには、[x]
演算子を用い、x
はusize
型のインデックスである。
fn main() {
let nums: [i32; 3] = [1, 2, 3];
println!("{:?}", nums);
println!("{}", nums[1]);
}
関数
関数は0個以上の引数があり、次の例ではi32
型の引数を2つとります。
関数名にはsnake_case
を使用する。
fn add(x: i32, y: i32) -> i32 {
return x + y;
}
fn main() {
println!("{}", add(42, 13));
}
関数の戻り値
値をタプルで返すことで複数の戻り値を返せる。
タプルの要素はインデックスで参照できる。
fn swap(x: i32, y: i32) -> (i32, i32) {
return (y, x);
}
fn main() {
// 戻り値をタプルで返す
let result = swap(123, 321);
println!("{} {}", result.0, result.1);
// タプルを2つの変数に分解
let (a, b) = swap(result.0, result.1);
println!("{} {}", a, b);
}
空の戻り値
戻り値の硬いが指定されていない場合、unitと呼ばれる空のタプルを返します。
空のタプルは()
と表記する。
fn make_nothing() -> () {
return ();
// 戻り値は () と明示
}
fn make_nothing2() {
// この関数は戻り値が指定されないため () を返す
// 戻り値は () と推論
}
fn main() {
let a = make_nothing();
let b = make_nothing2();
// 空を表示するのは難しいので、
// a と b のデバッグ文字列を表示
println!("a の値: {:?}", a);
println!("b の値: {:?}", b);
}
まとめ
変数の値のサイズ、変更の可否、計算を確実性を重視した言語設計になっている。