ここではRustの文法を簡単にまとめておきます。
目次
基礎文法 - Rustの特徴
基本的な型、変数の扱い、束縛
- 型:
- 数値、リテラル、浮動小数点数、論理値、文字型
- 複合型:
- タプル、配列型
- 参照と借用:
- 所有権の移動、借用
- 束縛:
- 束縛と可変変数、シャドーイング
- スコープ:
- ブロック単位、関数単位、構造体単位、クロージャ単位
文字列
- 文字:
- 文字を扱う、特殊文字、u8型へのキャスト
- 文字列:
- 文字列の扱い、アルファベットの操作、
- 日本語の扱い、日本語を正しく扱う
- 文字列スライス:
- 先頭を切り出すスライス、途中の文字列を切り出すスライス、
- 最後まで切り出すスライス、全体を切り出すスライス
文と式と関数
- 文と式:
- 文、式
- 演算子:
- 四則演算子、代入演算子、ビット演算子、シフト演算子、論理演算子、単項演算子
- 関数:
- 引数のない関数、引数のある関数、戻り値のある関数、
- 文字列を受け取る関数、文字列を戻す関数、
- ベクターを受け取る関数、ベクターを戻す関数、ベクターの中身を変更する関数
その他
- 制御文とパターンマッチ
- 配列とベクター
- 構造体とメソッド
- ジェネリクスとトレイト
- 所有権
- パッケージの作成
- ファイル入出力
- マクロ
- Web API呼び出し
- データベースアクセス
- C言語ライブラリの呼び出し
- クロージャ
- 並列化
- テストコード
参考書籍
基礎文法 - 型
型推論
-
Rustの場合は型推論させるのが一般的です。
型推論させた変数の使用例fn main() { let name = "fumo"; let age = 41; }
-
型を宣言しておきたいときは
:
の後に変数の型を書きます。型を宣言fn main() { let name : &str = "fumo"; let age : i32 = 41; }
-
文字列の型は
&str
。 -
数値の場合は主に
i32
を使います。i32
は整数(integer)の32ビット版です。 -
最近のパソコンでは64ビットが主流なので
i64
でもOKです。 -
変数だけの時は型を指定する必要はありません。(型推論でOK)
-
しかし、関数を作成する場合は型の指定が必須になります。
関数を作成する場合は型の指定が必須になるfn add(x: i32, y: i32) -> i32 { x + y }
-
fn
は関数宣言の印です。 -
add関数は引数xと引数yの2つを受け取って、加算して返すという簡単なものです。
-
->
が関数の戻り値です。 -
戻り値の型は関数の中で使われている計算結果の型と一致させなくてはならない。
コンパイルエラーfn add(x: i32, y: i32) -> i64 { x + y }
-
戻り値の型で指定した
i64
が間違っているためコンパイルエラーになります。 -
x + yの型を
i64
型に変換するか、add関数の戻り値の型をi32
型変更するかの2つの解決方法があります。
数値の型
ビット長 | 整数 | 符号なし整数 |
---|---|---|
8ビット | i8 | u8 |
16ビット | i16 | u16 |
32ビット | i32 | u32 |
64ビット | i64 | u64 |
処理系依存 | isize | usize |
数値のリテラル
数値リテラル | 例 |
---|---|
10進数 | 12_345 |
16進数 | 0xff |
8進数 | 0o77 |
2進数 | 0b1111_0000 |
1バイト | b'A' |
浮動小数点数
ビット長 | 浮動小数点数 | 備考 |
---|---|---|
32ビット | f32 | 単精度浮動小数点数 |
64ビット | f64 | 倍精度浮動小数点数 |
fn main() { let x = 100.234; println!("x is {}", x); let y : f64 = 100.234; println!("y is {}", y); }
論理値
true
とfalse
の2つのみ値を持つ。bool型
。
fn main() { let b = true; println!("b is {}", b); }
文字型
char型
を使います。- アルファベットやひらがななどをシングルクォート(
'
)で囲みます。fn main() { let c = 'A'; println!("c is {}", c); let c = 'あ'; println!("c is {}", c); let dog = '🐶'; println!("dog is {}", dog); let cat : char = '😸'; println!("cat is {}", cat); }
文字列型
&str型とString型
- Rustの文字列には
&str型
とString型
があります。 - 文字列の扱いは 所有権(ownership) や 借用(borrow) を特に気をつける必要があります。
println!マクロ
を使ってコンソールに表示するだけなら、以下サンプルで十分です。
ステークホルダー{}を指定したprintln!の使用例
fn main() { let dog = "DOG"; let cat = "CAT"; println!("{} and {}", dog, cat); }
出力結果
DOG and CAT
- ここで使われる方は
&str型
です。 let
を使って変数を使う限りは特に気にする必要はありません。
Rustの標準ライブラリString型を使う方法
String::from関数
fn main() { let s = String::from("Hello Rust!"); println!("{}", s); }
出力結果
Hello Rust!
String型
のfrom関数
を使って文字列の初期化ができます。- やっていることは
&str
と同じです。
- やっていることは
String型
にしておく理由は受け取った文字列を更新したいときに便利だからです。
更新の例「+」演算子
fn main() { let s1 = String::from("Hello"); let s2 = String::from("Rust"); let s3 = String::from("World."); let s = s1 + " " + &s2 + " " + &s3; println!("{}", s); }
出力結果
Hello Rust World.
s2
とs3
に&(アンパサンド)
がついているのは借用の印です。
実際はformat!マクロを使うと便利
format!マクロ
fn main() { let s1 = String::from("Hello"); let s2 = String::from("Rust"); let s3 = String::from("World."); let s = format!("{} {} {}", s1, s2, s3); println!("{}", s); }
出力結果
Hello Rust World.
format!マクロ
では数値や文字列を連結して1つの文字列にして返してくれます。
String::from関数
でなくて"(ダブルクォート)
を使って直接文字列を代入する方法でもformat!マクロ
は使えます。
直接文字列を代入する方法
fn main() { let s1 = "Hello"; let s2 = "Rust"; let s3 = "World."; let s = format!("{} {} {}", s1, s2, s3); println!("{}", s); }
出力結果
Hello Rust World.
- Rustの文字列の扱いはUTF-8と配列がややこしく絡み合っているので結構注意が必要です。
- あまりややこしいことをしなければ、
String::from関数
とformat!マクロ
でそこそこまでいけます。
複合型
- 複数の型をまとめて扱える型。
- 複合型には
タプル型
と配列型
の2つがある。
タプル型
- タプルとは「組」(Tuple)という意味で、2つの異なるものをひと組として扱う方法です。
- もともとタプル自体は2つをまとめたものを意味していましたが、いまでは複数の型をまとめるものをタプルと呼んでいます。
- タプルは
(
と)
の間に数値や文字列を入れて作ります。 ()
の中にはリテラルだけでなく変数を入れることもできます。- タプルの要素にアクセスするには
.
(ドット)に続いて添字(0始まり)を指定します。タプルの例fn main() { let name = "fumo"; let age = 40; let tuple = (name, age); println!("名前は{}で、年齢は{}です。", tuple.0, tuple.1); }
出力結果
名前はfumoで、年齢は40です。
配列型
配列型
は同じ型に連続的にアクセスしたいときに使います。- 似たような用途で使うものとしては
ベクター型
があります。 配列型
は固定であり、後から長さを変えたり要素(配列の中身)を変えたりすることができません。ベクター型
は要素の追加や削除、更新などができます。- 要素にアクセスするには
[
]
にインデックスを添え字として指定しアクセスします。 - 要素数を超えてアクセスしようとするとビルド時にエラーとなります。
配列の例
fn main() { let array = ["春", "夏", "秋", "冬"]; println!("最初の季節 {}", array[0]); println!("最後の季節 {}", array[3]); }
出力結果
最初の季節 春 最後の季節 冬