(-> % read write unlearn)

My writings on this area are my own delusion

rust-lang#04 ifとforループ

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> { ... } Rubyfor 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

ラベルなしで使うbreakcontinueは、最も内側のループを終了/スキップします。 ラベルというのを使うとどのループに対して終了/スキップするかを明示できます。

ラベルは'<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

感想

  • breakcontinue、ラベルあたりは普通な感じでした!
  • loopは必要なのかな―。whileで足りている気がします。
  • 0..30,1,2終端を含まない、は忘れないように。

次はVectors!それ終わったらいよいよOwnershipだ!わくわく。