Rustの文のメモ。
Rustのifやmatch・ループは文として使うことも出来るが、式として値を返すことも出来る。
ifやwhile等の条件式の部分は、C言語やJavaだと丸括弧で囲むが、Rustでは丸括弧で囲まない。
条件式と処理本体との境界をはっきりさせる為に、処理本体は必ず波括弧で囲む。波括弧抜きでひとつの文だけを書くことは出来ない。
波括弧で囲んで複数の文を書ける。
ブロックがローカル変数のスコープ(変数が存在できる範囲)となる。
{ 文; 〜 文; }
波括弧内の最後の式の値がブロックの値になる。
この場合、最後の式の末尾にセミコロン「;
」を付けてはいけない。
(セミコロンを付けると、ブロックの値は()
(ユニット型の唯一の値)になる)
{ 文; 〜 文; 式 }
let n = { let a = 1; let b = 2; a + b // ブロックの値(末尾にセミコロンを付けない) }; println!("n = {}", n);
if 条件式 { 〜 }〔else if 条件式 { 〜 } 〕〔else { 〜 } 〕
if n % 15 == 0 { println!("{} FizzBuzz", n); } else if n % 3 == 0 { println!("{} Fizz", n); } else if n % 5 == 0 { println!("{} Buzz", n); } else { println!("{}", n); }
let s = if n % 15 == 0 {
String::from("FizzBuzz")
} else if n % 3 == 0 {
String::from("Fizz")
} else if n % 5 == 0 {
String::from("Buzz")
} else {
n.to_string()
}; // このセミコロンは、letの末尾
println!("{} {}", n, s);
match 値 { パターン1 => 処理1, パターン2 => 処理2, パターン3 => { 〜 } // 波括弧でブロックを作った場合は、末尾カンマは不要 … }
複数の「パターン => 処理」はカンマで区切る。最後の処理の末尾にカンマがあっても無視される。
それぞれの「パターン => 処理」が別々のスコープを持つ。(異なるパターンにおいて同名の変数を使うことが出来る)
(Javaのswitchだと、switchブロックがひとつのスコープになり、異なるcaseで同名の変数を宣言することは出来ない)
処理に複数の文を書きたい場合は波括弧で囲んでブロックにする。
その際は、ブロックの終わりの直後にカンマは不要。
matchでは網羅性チェックが行われる。
パターンの例 | 説明 | 例 |
---|---|---|
値 | ひとつの値。 |
let n : i32 = 0; match n { 0 => "zero", 〜 } |
_ (アンダースコア) | 全てにマッチする。 |
match n { 〜 _ => "default", } |
値1 | 値2 | 値3 | 複数の値。 |
match n { 1 | 2 | 3 => "little", 〜 } |
開始.. 終了 |
範囲(終了は含まない)。 開始 <= 値 && 値 < 終了 |
match n { 1..3 => "little", 〜 } |
開始..= 終了 |
範囲(終了も含む)。 開始 <= 値 && 値 <= 終了 |
match n { 1..=3 => "little", 〜 } |
パターンマッチ | OptionとかResultとか。 |
let o : Option<i32> = Some(123); match o { Some(n) => println!("n = {}", n), None => println!("none"), } |
パターン if 条件式 | ガード条件。 |
match o { Some(n) if n >= 100 => println!("{} large", n), Some(n) => println!("{} small", n), None => println!("none"), } |
if letはmatchの特別なケースのようなもの。
「ひとつのパターンにだけ合致すればよく、合致しなかった値に対しては何もしない」ような場合に便利。
if let パターン = 値 { 〜 }〔else { 〜 } 〕
if letの例 | matchで書いた場合 |
---|---|
let o : Option<i32> = Some(123); if let Some(n) = o { println!("n = {}", n); } |
let o : Option<i32> = Some(123); match o { Some(n) => println!("n = {}", n), _ => {}, } |
「Some(n) = o
」は、代入形式であり、「==
」による比較ではない。
値o
がパターンSome(n)
に合致する場合に限り、処理が実行される。
loopは無限ループ。
breakでループから抜ける。(returnで関数から抜けてもいい)
loop { 〜 }
機能的には「while true」と同じだが、loopの方が条件判定しない分だけ速いらしい。
let mut n = 0; loop { println!("n = {}", n); n += 1; if n >= 5 { break; } }
whileは条件を満たす間ループする。
while 条件式 { 〜 }
let mut n = 0; while n < 5 { println!("n = {}", n); n += 1; }
forはイテレーターの要素を順番に処理する。
for 変数 in イテレーター { 〜 }
変数を使わない場合は「_」(アンダースコア)にする。
説明 | 例 | Java相当 | Scala相当 |
---|---|---|---|
10回繰り返す(0〜9) |
for i in 0..10 { println!("{}", i); } |
for (int i = 0; i < 10; i++) { System.out.println(i); } |
for (i <- 0 until 10) { println(i) } |
1から10まで |
for i in 1..=10 { println!("{}", i); } |
for (int i = 1; i <= 10; i++) { System.out.println(i); } |
for (i <- 1 to 10) { println(i) } |
コレクション |
let array = [1, 2, 3]; for elem in array { println!("{}", elem); } |
final int[] array = { 1, 2, 3 }; for (var elem : array) { System.out.println(elem); } |
val array = Array(1, 2, 3) for (elem <- array) { println(elem) } |
変数を使わない場合 |
for _ in array { println!("."); } |
for (var _ : array) { System.out.println("."); } |
for (_ <- array) { println(".") } |
コレクションのインデックス付き |
for (i, elem) in array.iter().enumerate() { println!("{}: {}", i, elem); } |
int i = 0; for (var elem : array) { System.out.printf("%d: %d\n", i, elem); i++; } |
for ((elem, i) <- array.zipWithIndex) { println(s"$i: $elem") } |
breakでループ(loop・while・for)から抜ける。
break 〔'ラベル〕 〔値〕;
ループにラベルを付けてbreakにそのラベルを指定すると、そのループから抜ける。二重ループを抜けるのに便利。
ラベルの命名ルールとして、ラベル名の先頭にアポストロフィー「'
」を付ける。(ライフタイムと同じ命名ルール)
breakに値を指定すると、その値がループの戻り値になる。
'loop1: for i in 0..5 { for j in 0..3 { if i == 3 && j == 1 { break 'loop1; } println!("i={}, j={}", i, j); } }
let r = loop { 〜 break 123; };
continueでループ(loop・while・for)の先頭に戻る。
(forの場合、次の要素へ移る)
continue 〔'ラベル〕;
ラベルに関してはbreakと同様。
'loop1: for i in 0..5 { for j in 0..3 { if i == 3 && j == 1 { continue 'loop1; } println!("i={}, j={}", i, j); } }