Rustの勉強まだ続いてます。 前回の Primitive Types と Commentsに続いてhttps://doc.rust-lang.org/bookをやっていきます。
今日は4.5. ifからです。
4.5. if
Rustのif
は式です。つまり、値を返します。
その他は一般的なif
と同様な感じです。Rubyのifに近いですね。
fn main() { let num: u32 = 1; let num_text = if num == 0 { "zero" // ←値を返したいので、セミコロンは付けない。 } else if num == 1 { "one" // ←値を返したいので・・・ } else { "more than one" // ←値を返・・・ }; // ←逆に、ここにはセミコロン必須。num_textへの束縛のステートメントの終わりなので。 println!("{} is {}", num, num_text); //=> 1 is one // 上記のif文は1行でも書ける。 let num_text2 = if num == 0 { "zero" } else if num == 1 { "one" } else { "more than one" }; println!("{}", num_text2); //=> one }
else
節のないif
式は、常に空のタプル()
を返すことに注意してください。
fn main() { let num: u32 = 1; let num_text = if num == 0 { "zero" } else if num == 1 { "one" }; }
のように書くと、if may be missing an else clause:
というコンパイルエラーになります。
ここらへんはRubyと大きく違う感じですね。
Rubyの場合はelseがなくてもsyntax的には問題ないし、elseがなくてelseに分岐するような場合の返り値はnil
です。
Rustでは、安全性のために明示しないといけなくなっています。
# Ruby 2.0.0 num = 1 num_text = if num == 0 then "zero" elsif num == 1 then "one" end p num_text #=> "one" num_text2 = if num == 0 then "zero" end p num_text2 #=> nil
4.6. Loops
Loops
Rustで繰り返しを表現する構文は3つです。
機能 | 構文 | 説明 | |
---|---|---|---|
1 | loop |
loop { ... } |
while true { ... } 相当です。 |
2 | while |
while <condition> { ... } |
一般的なwhile と同じです。 |
3 | for |
for <var> in <expression> { ... } |
Rubyのfor in に近いです。 |
(1) loop
loop { println!("無限ループで、さようなら〜・・・"); }
(2) while
一般的なwhile
と同様な感じです。
繰り返しの回数が定かではなかったり動的であったりする場合に用います。
fn main() { let mut i = 1; while i % 4 != 0 { print!("{} ", i); i += 1 } //=> 1 2 3 }
while true
を使う場面では、より意図が明確かつ簡潔なloop
のほうが好ましいです。
(3) for
Rustのforは、古典的な外部イテレータを使う構文はサポートしていません。 Rubyのforによく似ています。
fn main() { for x in 0..5 { print!("{},", x); // x: i32 } //=> 0,1,2,3,4 }
ただし、RubyとRustではドット2つのときの挙動が違います。 ごっちゃになりそうです。。
ドットの数 | 終端を含む? | サンプルコード | 出力 | |
---|---|---|---|---|
Rust | 2つ.. |
終端を含まない | for x in 0..5 { print!("{}", x); } |
01234 |
Ruby | 2つ.. |
終端を含む | for x in 0..5 do print x end |
012345 |
Ruby | 3つ... |
終端を含まない | for x in 0...5 do print x end |
01234 |
in
に渡した式(ここでは0..5
)は、IntoIteratorを用いてiteratorに変換されます。
変換不可能なものは渡せません。
Enumerate
繰り返しのインデックスが欲しい場合には、.enumerate()
メソッドが使えます。
fn main() { for (i,j) in (11..15).enumerate() { println!("{} 回目の値は {} です。", i+1, j); } } //=> 1 回目の値は 11 です。 //=> 2 回目の値は 12 です。 //=> 3 回目の値は 13 です。 //=> 4 回目の値は 14 です。 //=> 5 回目の値は 15 です。
文字列を改行コードでイテレート。
fn main() { for (linenumber, line) in "foo\nbar\nbaz\n".lines().enumerate() { println!("{} 行目:{}", linenumber+1, line); } } //=> 1 行目:foo //=> 2 行目:bar //=> 3 行目:baz
Ending iteration early
途中でイテレーションを終了するbreak
fn main() { for x in 0..10 { if x >= 5 { break; } print!("{},", x); } //=> 0,1,2,3,4, }
その回のイテレーションのそれ以降の処理をスキップするcontinue
fn main() { for x in 0..10 { if x < 5 { continue; } print!("{},", x); } //=> 5,6,7,8,9, }
Loop labels
ラベルなしで使うbreak
やcontinue
は、最も内側のループを終了/スキップします。
ラベルというのを使うとどのループに対して終了/スキップするかを明示できます。
ラベルは'<label> for ... in { ... break/continue '<label>; ... }
のように使います。ラベル名の先頭はシングルクォートです。
fn main() { 'A: for x in 0..5 { 'B: for y in 0..5 { if y >= 3 { break 'A; } println!("x: {}, y: {}", x, y); } } } //=> x: 0, y: 0 //=> x: 0, y: 1 //=> x: 0, y: 2
fn main() { 'A: for x in 0..5 { 'B: for y in 0..5 { if y >= 3 { break 'B; } // この場合 if y >= 3 { break; } でも同じ println!("x: {}, y: {}", x, y); } } } //=> x: 0, y: 0 //=> x: 0, y: 1 //=> x: 0, y: 2 //=> x: 1, y: 0 //=> x: 1, y: 1 //=> x: 1, y: 2 //=> x: 2, y: 0 //=> x: 2, y: 1 //=> x: 2, y: 2 //=> x: 3, y: 0 //=> x: 3, y: 1 //=> x: 3, y: 2 //=> x: 4, y: 0 //=> x: 4, y: 1 //=> x: 4, y: 2
感想
break
、continue
、ラベルあたりは普通な感じでした!loop
は必要なのかな―。while
で足りている気がします。0..3
は0,1,2
で終端を含まない、は忘れないように。
次はVectors!それ終わったらいよいよOwnershipだ!わくわく。