Category prog.

コンテキストについて学んだよ。今回もとぴあさんくらむさんに親切に教えてもらったよ。

Perl ではコンテキストっていうのがあって、意識していないとハマるらしい (というかハマった)。サブルーチンを呼ぶところだけを見ても、そのサブルーチンが何を返すかがわからない。

$ perlsh
main[1]$ @arr = localtime;
56
21
1
18
4
106
4
137
0
main[2]$ $scr = localtime;
Thu May 18 01:22:02 2006

最初、なんでただの配列がスカラ変換のときに、タイムオブジェクト?のように見なされて時刻文字列になるんだ?って思ったんだけど、これは localtime がコンテキストによって挙動を変えた (!) 結果らしい。localtime っていう部分だけを見ても、localtime が何を返すかはわからない。


そのコンテキストとやらには、大きくわけてリストコンテキスト・スカラコンテキスト・void コンテキストがあるようだ。

sub context {
if (defined wantarray) { # void context では undef
if (wantarray) { # list context では true
print "List Context!\n";
} else {
print "Scalar Context!\n";
}
} else {
print "void Context!\n";
}
return;
}
@arr = context;
$scr = context;
context;
__END__
List Context!
Scalar Context!
void Context!

という感じで、サブルーチン内で wantarray を呼ぶことによりコンテキストの分岐ができる。wantarray っていう名前はおかしい (配列とリストは区別がある) みたいだけど、歴史的事情がきっとあるんだろう? perldoc でも wantlist であるべきだった的なことが書いてある。

たぶんコンテキストの理解は Perl では必須だろうけど、こういうのって他の言語だとあんまり見ないよね、っていう感じだった。


他今日知ったこと

  • use vars は obsolete。変わりに our
  • 擬似ハッシュには触るな (obsolete)
  1. トップ
  2. perl
  3. 今日のぺるる コンテキスト
  1. トップ
  2. prog
  3. 今日のぺるる コンテキスト

grep とリファレンスがわからなかった。

ちなみに一通りドキュメントは読んでみて、概念っぽいのはわかっているんだけど、実際の挙動がわからない、という感じ。ようするにだめだめ。とぴあさんに助けてもらいつつちょっとわかってきた。

[{:foo=>:a, :bar=>:b}, {:foo=>:c, :bar=>:d}].find {|i| i[:foo] == :a}[:bar]

っていう Ruby のコードを Perl で書きたい場合。

# 答え
(grep { $_->{foo} eq "a"} [{foo=>"a", bar=>"b"}, {foo=>"c", bar=>"d"}])[0]->{bar};
#以下間違い
# クロージャのあとにカンマは要らない
grep { .. }, [..];
# -> 演算子によって左辺がスカラ文字列に変換されてしまうらしい
# この場合 grep でヒットした配列の数の文字列に対してハッシュ操作を
# 行おうとするので、エラー
(grep { .. } [])->{bar};

リファレンスを実データに戻す文法がわからなかった。

$a = [1, 2, 3]; #=> $a is reference of array
@{$a}; #=> で array に戻る
# @($a) と書いて構文エラー

それと Hash ref, Array ref から直接アロー演算子使って中身を取り出すときの構文

$a = ["a", "b", "c"];
$a->[1]; #=> "b"
$h = {0 => "a", 1 => "b", 2 => "c"};
$h->{1}; #=> "b"

一番なるほど!て思ったのは $_

grep { $_ eq "a" } ("a", "b", "c");
foreach (@{$a}) {
print $_;
}

$_ ってよく見るけどなんやねんって思ってた。

grep {|$_| ..}

っていう Ruby 風の説明をされてよくわかった。


疑問

foreach (@{$a}) {
foreach (@{$b}) {
$_;
}
$_; #=> スコープは?
}

あとで実行してみよう。

foreach $i (@{$a}) {
foreach $j (@{$b}) {
print "$i, $j";
}
}

みたいにかけるのかな。my をつけるべき? (つけられる?) っていうか for と foreach は同じなのね

コメントでの指摘で修正

  1. トップ
  2. perl
  3. 今日のぺるる - grep, リファレンス
  1. トップ
  2. prog
  3. 今日のぺるる - grep, リファレンス