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);
}
}