Ruby の next 、ついでに Perl も

Ruby の next は引数を取れる

next はループのなかで使って、後続の処理をスキップして次のターンに行くというのが役割だと思っていたけど、Ruby では yield 呼び出しの脱出にも next を使う。

nextはもっとも内側のループの次の繰り返しにジャンプします。 イテレータでは、yield 呼び出しの脱出になります。 next により抜けた yield 式は nil を返します。 ただし、引数を指定した場合、yield 式の戻り値はその引数になります。

http://docs.ruby-lang.org/ja/2.1.0/doc/spec=2fcontrol.html#next

なるほど〜

たしかに言われてみれば自然。でもループっぽくないブロックもあるから、今日ちょっと「あれっ?」と思ったのだった。

何の意味もないけど、適当にこういうコードを書いて実行してみる。

#!/usr/bin/env ruby

class Foo
  def self.bar(n)
    (1..n).each do |i|
      ret = yield i
      p ret
      break if ret == 'hi'
    end
  end
end

Foo.bar(10) do |i|
  next 'hi' if i == 3
end

出力結果はこうなる。

nil
nil
"hi"

ふむふむ。

一方 Perl では

Perl でも next に引数を指定できる。

next LABEL

http://perldoc.perl.org/functions/next.html

これはループの先頭にラベルを付けておいて next LABEL とすると、ネストしたループの中からラベルのついたループまで脱出できるというやつだ。それは知っていたけど、ひさしぶりにドキュメントみたらこういうのを見つけた。

The next EXPR form, available as of Perl 5.18.0, allows a label name to be computed at run time, being otherwise identical to next LABEL .

つまり、next の引数に式を指定できて、その評価結果がラベルとして使われるようだ。5.18.0 から。

試しに以下のようなコードを書いてみたけど、もはや何がしたいのかわからなくなってきた。

#!/usr/bin/env perl
use strict;
use warnings;

LINE:
while (my $line = <>) {
    chomp($line);
    print "line: $line\n";

    FIELD:
    foreach my $field (split /,/, $line) {
        next uc($field) if $field =~ /\A(?:line|field)\z/;
        print "field: $field\n";
    }
}

実行すると標準入力を1行ずつ受け取って while ループが実行される。 実行結果はこんな感じになる。

aaa,bbb,ccc
line: aaa,bbb,ccc
field: aaa
field: bbb
field: ccc
aaa,line,ccc
line: aaa,line,ccc
field: aaa
aaa,field,ccc
line: aaa,field,ccc
field: aaa
field: ccc

おわり。