perltrap - 不注意による Perl の罠
最も大きな罠とは、use warnings
あるいは -w スイッチを使うのを 忘れてしまうということです; perllexwarn と perlrun を 参照してください。 二番目に大きな罠とは、あなたのプログラム全体を use strict
の元で 実行しないということです。 三番目の罠は、このバージョンの Perl での変更点を読まないということです; perldelta を参照してください。
awk に慣れた方は、以下のようなことに特に注意してください:
Perl のプログラムは、1 度だけ実行されます; 入力行毎ではありません。 -n
や -p
を使って暗黙のループを使えます。
Englishモジュールを
use English;
のようにしてロードすれば、awk でそうであったように ($/
のような)特殊変数を($RS のような)名前で参照することができます; 詳しくは perlvar を参照してください。
Perlでは、すべての単純文(simple statement)の末尾にセミコロンが必要です (ブロックの最後に置かれたときを除きます)。 改行は文の区切りとはなりません。
if
や while
では中かっこが必要です。
Perlでは、変数は“$”"か“@”か“%”で始まります。
配列の添え字は 0 から始まります。 substr() や index() での文字列の位置も同様です。
配列の添え字が数値であるか、文字列であるかを決めなければなりません。
ハッシュ(連想配列)の値は、単に参照するだけでは存在することに なりません。
比較を文字列によって行うのか、数値によって行うのかを 決めなければなりません。
入力を読み込むだけでは split は行われません。 配列への split は自分で行います。 また、split() 演算子の引数は awk のものと異なっています。
通常、カレント行は $0 ではなく $_ にあります。 一般的に、改行は取り除かれません。 ($0 には実行しているプログラムの名前があります)。 perlvar を参照してください。
$<digit> はフィールドを参照しません--これは直前に行った パターンマッチングの部分文字列を参照します。
print() 文は、$,
や $\
に値を設定しない限りフィールド区切り子や レコード区切り子を付加しません。 English モジュールを使っていれば、$OFS や $ORS に対して設定することでも OK です。
ファイルに対して出力する前には、そのファイルをあらかじめオープンして おかなければなりません。
範囲演算子は“..”であって、カンマではありません。 カンマ演算子は C と同じような振る舞いをします。
マッチ演算子は“=~”であって、“~”ではありません。 (“~”はCと同様に、1の補数を取る演算子です。)
べき乗の演算子は“**”であって、“^”ではありません。 “^”は C と同様、XOR 演算子です。 (awk が基本的に C と非互換であることにお気付きかもしれませんね。)
連接演算子は“.”であって、空文字列ではありません。 (空文字列を使ってしまうと /pat/ /pat/
が、その 3 番目のスラッシュが 除算演算子と解釈されてしまうので正しく解析できなくなります-- Perl の字句解析器は "/", "?", ">" といった演算子に対して 多少文脈依存となっています。 実際、"." 自身も数値の始まりとなる可能性もあります。)
キーワード next
, exit
, continue
の振る舞いが異なります。
以下の変数の働きが異なります。
Awk Perl
ARGC scalar @ARGV (compare with $#ARGV)
ARGV[0] $0
FILENAME $ARGV
FNR $. - something
FS (whatever you like)
NF $#Fld, or some such
NR $.
OFMT $#
OFS $,
ORS $\
RLENGTH length($&)
RS $/
RSTART length($`)
SUBSEP $;
$RS に正規表現をセットすることはできません; できるのは文字列だけです。
妙だと思ったときには awk の構文を a2p に通して、出力されたものを 見てみましょう。
知的な C と C++ のプログラマは以下のことに注意すべきです:
if
や while
には中かっこが必要です。
else if
ではなく、elsif
を使わなければなりません。
C の break
と continue
は、Perl ではそれぞれ last
と next
となります。 C とは異なり、これらは do { } while
構文では 使えません。 "Loop Control" in perlsyn を参照してください。
switch 文は given/when
と呼ばれ、perl 5.10 以降でのみ利用可能です。 "Switch Statements" in perlsyn を参照してください。
Perlでは、変数は“$”"か“@”か“%”で始まります。
コメントの始まりは、“#”であり、“/*”や "//" ではありません。 Perl は C/C++ のコメントを除算演算子、終端していない正規表現、 定義性和演算子として解釈するかもしれません。
なにかのアドレスを得ることはできません; Perl には似たような演算子である バックスラッシュがありますが、これはリファレンスを生成します。
ARGV
は大文字でなければなりません。 $ARGV[0]
が C での argv[1]
に相当し、argv[0]
にあたるものは $0
です。
link(), unlink(), rename() などのシステムコールは、成功時に 0 ではなく非 0 の値を返します。 (但し、system() は成功時に 0 を返します。)
シグナルハンドラは、シグナル番号ではなくシグナル名を扱います。 使用できるシグナル名は、kill -l として確かめてください。
熟練した sed プログラマは以下のことに注意すべきです:
Perl のプログラムは、1 度だけ実行されます; 入力行毎ではありません。 -n
や -p
を使って暗黙のループを使えます。
置換における後方参照には、“\”ではなく“$”を使います。
"(", ")", "|" といったパターンマッチのメタキャラクタは、その直前に バックスラッシュを置く必要はありません。
範囲演算子は ...
であって、カンマではありません。
鋭いシェルプログラマは以下のことに注意すべきです:
バッククォート演算子は、コマンド内にシングルクォートがあっても 変数の展開を行ないます。
バッククォート演算子は csh とは違って、返された値を変換しません。
シェル (特に csh) は、コマンドラインごとに何段階もの置換を行ないます。 Perl はダブルクォート、バッククォート、山かっこ、検索パターンといった 特定の構造でだけ置換を行ないます。
シェルは一度に少しずつ解釈を行ないます。 Perl は実行前にプログラム全体をコンパイルします (コンパイル時に実行される BEGIN
ブロックを除く)。
引数は $1, $2 などではなく、@ARGV から得られます。
環境変数は、自動的には独立したスカラ変数として利用できるように なりません。
シェルの test
は "=", "!=", "<" などを文字列比較に使い、"-eq", "-ne", "-lt" などを数値比較に使います。 これは Perl とは逆です; Perl では eq
, ne
, lt
を文字列比較に使い、 ==
, !=
<
などを数値比較に使います。
実践的な Perl プログラマは以下のことに注意すべきです:
多くの演算子がリストコンテキストとスカラコンテキストとで 振る舞いが変わることを忘れないでください。 詳しくは perldata を参照してください。
裸の単語、特に全てが小文字のものはできる限り使わないでください。 見た目だけではその「裸の単語」が関数なのか、 文字列なのかが判断できません。文字列にはクォートを、 関数呼び出しには括弧をつければ、迷うこともないでしょう。
組込み関数のどれが(chop() や chdir())のような単項演算子で、 どれが(print() や unlink())のような リスト演算子であるかは見ただけではわかりません。 (プロトタイプがなければ、ユーザー定義サブルーチンは リスト演算子として のみ 定義でき、単項演算子にはできません。) perlop と perlsub を参照してください。
いくつかの関数が $_ や @ARGV などをデフォルトにしていますが、 同じことを期待する他の関数がデフォルトになっていないことを覚えるのに、 辛いタイピングが必要でしょう。
<FH> 構造はファイルハンドルではなく、そのハンドルに対する行読み込みの 操作(readline operation)です。 while ループの条件式の中にこのファイル読み込みだけがあった場合には 読み込まれたデータは $_ に代入されます。
while (<FH>) { }
while (defined($_ = <FH>)) { }..
<FH>; # data discarded!
=~
が必要なところで c<=> を使わない、ということを忘れないでください; これら二つの構造はかなり違います:
$x = /foo/;
$x =~ /foo/;
do {}
構造は、ループ制御を行えるような本当のループではありません。
ローカル変数は、my() で済むところではこれで済ませること (使えない場所については、perlform を参照してください)。 local() を使えばグローバル変数に対するローカルな値を与えますが、 動的スコープの不慮の副作用の可能性は、そのままです。
モジュールにある export された変数を局所化すると、その export された 値は変更されません。 ローカル名は新しい値の別名(alias)となりますが、 外部名は元々の値の別名のままです。
実践的な Perl4 プログラマは 以下に挙げる Perl4 と Perl5 の違いに特有な罠に気をつけた 方が良いでしょう。
以下は順不同のリストです。
修正された perl4 のバグや、なくなった perl4 の仕様、 perl5 で仕様の変わったもの。
新しい構文解析器によって引き起こされるもの。
数値や算術演算子に関する罠。
perlの標準的なデータ型に内包される罠。
リスト内のコンテキストや、スカラ文/宣言に関する罠。
構文解析、評価、コードの実行の優先順に関係した罠。
パターンマッチングの仕様に関する罠。
シグナル及びシグナルハンドラ、一般的なサブルーチン、ソート、 ソートのためのサブルーチンに関連した罠。
OS特有の罠。
dbmopen()
の使用や、dbm の実装に関連した罠。
その他の罠。
もしここで挙げたリストにはないような変換の罠の 例を見つけたら、それを <perlbug@perl.org> まで送ってください。 また、少なくともこれらのいくつかは use warnings
プラグマか -w スイッチで捕捉できることに注意してください。
perl4 から、なくなったり修正されたことがら。
Symbols starting with "_" no longer forced into main@@@@@@@@@@"_" で始まるシンボルはもはや main パッケージに強制的に結び付けられません
“_”で始まるシンボルはもはや main パッケージに強制的に結び付けられることは、 $_
自身(と @-
など)を除いてはなくなりました。
package test;
$_legacy = 1;
package main;
print "\$_legacy is ",$_legacy,"\n";
# perl4 prints: $_legacy is 1
# perl5 prints: $_legacy is
Double-colon valid package separator in variable name@@@@@@@@@@ダブルコロンは変数名の中で有効なパッケージセパレータです
ダブルコロンは、変数名の中でパッケージセパレータになるようになりました。 このため、以下の例では perl4 と perl5 とでは振る舞いが変わります。 これはパッケージが実在してないためです。
$a=1;$b=2;$c=3;$var=4;
print "$a::$b::$c ";
print "$var::abc::xyz\n";
# perl4 prints: 1::2::3 4::abc::xyz
# perl5 prints: 3
::
は今では、(これがバグとして分類すべきかどうかはともかく) パッケージデリミタとしてみなされるようになっています。 (ここでは古いパッケージデリミタの ' を使っています)
$x = 10;
print "x=${'x}\n";
# perl4 prints: x=10
# perl5 prints: Can't find string terminator "'" anywhere before EOF
常にパッケージ名を含めることで、この問題を避けつつ、perl4 との 互換性を維持することができます:
$x = 10;
print "x=${main'x}\n";
$:
の解析については、優先順位の罠 も参照してください。
2nd and 3rd args to splice()
are now in scalar context@@@@@@@@@@splice()
の第 2、第 3 引数はスカラコンテキストになりました
splice()
の第 2、第 3 引数は (ラクダ本にある通り)リストコンテキストではなく スカラコンテキストで評価されるようになりました。
sub sub1{return(0,2) } # return a 2-element list
sub sub2{ return(1,2,3)} # return a 3-element list
@a1 = ("a","b","c","d","e");
@a2 = splice(@a1,&sub1,&sub2);
print join(' ',@a2),"\n";
# perl4 prints: a b
# perl5 prints: c d e
Can't do goto
into a block that is optimized away@@@@@@@@@@最適化によってなくなってしまうようなブロックの中に飛び込む goto
は使えません
最適化によってなくなってしまうようなブロックの中に 飛び込む goto
は使えなくなりました。 ちぇっ。
goto marker1;
for(1){
marker1:
print "Here I is!\n";
}
# perl4 prints: Here I is!
# perl5 errors: Can't "goto" into the middle of a foreach loop
Can't use whitespace as variable name or quote delimiter@@@@@@@@@@空白を変数名やクォートの区切りに使えません
空白を変数の名前や、クォート構造の区切りに使うことは 構文的に正当なものではなくなりました。ちぇっ、ちぇっ。
$a = ("foo bar");
$b = q baz ;
print "a is $a, b is $b\n";
# perl4 prints: a is foo bar, b is baz
# perl5 errors: Bareword found where operator expected
while/if BLOCK BLOCK
gone@@@@@@@@@@while/if BLOCK BLOCK
対応はなくなりました
古い while/if BLOCK BLOCK の構文は、もはやサポートされていません。
if { 1 } {
print "True!";
}
else {
print "False!";
}
# perl4 prints: True!
# perl5 errors: syntax error at test.pl line 1, near "if {"
**
binds tighter than unary minus@@@@@@@@@@**
は単項のマイナスよりも優先順位が高いです
**
演算子の優先順位は、単項のマイナスよりも高くなりました。 これは以前からドキュメントにはそうあったのですが、実際は違っていました。
print -4**2,"\n";
# perl4 prints: 16
# perl5 prints: -16
foreach
changed when iterating over a list@@@@@@@@@@リストを反復するときの foreach
が変わりました
配列ではないリストに対する繰り返しで あるときの foreach{}
の意味が変わりました。 以前はそういったリストはテンポラリな配列に代入されていましたが、 現在はそうではありません(効率上の理由です)。 これは、現在では値のコピーに対して繰り返しをするのではなく 実際の値に対して繰り返しをするということです。 ループ変数の変更により元の値を変更できます。
@list = ('ab','abc','bcd','def');
foreach $var (grep(/ab/,@list)){
$var = 1;
}
print (join(':',@list));
# perl4 prints: ab:abc:bcd:def
# perl5 prints: 1:1:bcd:def
perl4 と同じようにするには、自分で陽にテンポラリの配列へと コピーしてからその配列に対して繰り返しを行います。 例えば、次のものを変更する必要があるかもしれません:
foreach $var (grep(/ab/,@list)){
このように:
foreach $var (@tmp = grep(/ab/,@list)){
そうしないと、$var を変更したときに @list の値に影響が出ます。 (これはループ変数に $_
を使っていて、かつ、 $_
を局所化していないようなサブルーチンを ループの中で呼ぶようなときに良く起こります。)
split
with no args behavior changed@@@@@@@@@@引数なしの split
の振る舞いが変わりました
引数なしの split
の振る舞いは、split /\s+/
($_ が空白から始まっているときに先頭のフィールドが空になる)
$_ = ' hi mom';
print join(':', split);
# perl4 prints: :hi:mom
# perl5 prints: hi:mom
-e behavior fixed@@@@@@@@@@-e の振る舞いが修正されました
perl4 では、-e スイッチにアタッチされたテキストは無視されて、常に 後に続く引数からプログラムが取り出されていました。さらに、 -e スイッチの後に引数を渡さない場合も受け付けていました。 これらの振る舞いは両方とも修正されました。
perl -e'print "attached to -e"' 'print "separate arg"'
# perl4 prints: separate arg
# perl5 prints: attached to -e
perl -e
# perl4 prints:
# perl5 dies: No code specified for -e.
push
returns number of elements in resulting list@@@@@@@@@@push
は結果リストの要素数を返すようになりました
Perl 4 では push
の戻り値はドキュメントに書かれていませんでしたが、 実際には対象となるリストに最後にpushした値が返されていました。 Perl 5 では、push
の戻り値はドキュメントに明記され、かつそれは 変更されました; これは push した後のリストにある要素の数を返します。
@x = ('existing');
print push(@x, 'first new', 'second new');
# perl4 prints: second new
# perl5 prints: 3
Some error messages differ@@@@@@@@@@一部のエラーメッセージが異なっています
一部のエラーメッセージが異なっています。
split()
honors subroutine args@@@@@@@@@@split()
はサブルーチンの引数を尊重します
Perl 4 では、リストコンテキストで split()
の最初の引数の デリミタが ??
だった場合、返される結果が @_
にも設定されました。 Perl 5 ではサブルーチンの引数により多くの敬意を払います。
Bugs removed@@@@@@@@@@バグが修正されました
幾つかのバグがうかつにも修正されているかもしれません。 :-)
パースに関する Perl4 と Perl5 の違いの罠です。
Space between . and = triggers syntax error@@@@@@@@@@. と = の間に空白を入れると文法エラーになります
. と = の間にあるスペースに注意。
$string . = "more string";
print $string;
# perl4 prints: more string
# perl5 prints: syntax error at - line 1, near ". ="
Better parsing in perl 5@@@@@@@@@@perl 5 でのよりよいパース
perl5 では構文解析が改良されました。
sub foo {}
&foo
print("hello, world\n");
# perl4 prints: hello, world
# perl5 prints: syntax error
Function parsing@@@@@@@@@@関数のパース
“それが関数に見えるのなら、それは関数だ”のルール。
print
($foo == 1) ? "is one\n" : "is zero\n";
# perl4 prints: is zero
# perl5 warns: "Useless use of a constant in void context" if using -w
String interpolation of $#array
differs@@@@@@@@@@$#array
の文字列展開が異なります
$#array
構造の文字列展開で名前の周りにブレースがあるときには 違いがあります。
@a = (1..3);
print "${#a}";
# perl4 prints: 2
# perl5 fails with syntax error
@a = (1..3);
print "$#{a}";
# perl4 prints: {a}
# perl5 prints: 2
Perl guesses on map
, grep
followed by {
if it starts BLOCK or hash ref@@@@@@@@@@Perl は map
, grep
の後の {
が BLOCK の開始かハッシュリファレンスかを推測します
perl が map {
(または grep {
) を見つけると、{
が BLOCK の開始か ハッシュリファレンスかを推測します。 推測に失敗すると、}
の近くでカンマがない (あるいは予想外の位置に カンマがある) という文法エラーが報告されます。
ハッシュリファレンスの {
の前に単項の +
を、また BLOCK 内の最初の ものに({
の後に) 単項の +
を使ってください; perl がいつでも正しく 推測できるようにするためです。 ("map" in perlfunc を参照してください。)
同じものに対する数値演算子、オペランド、出力に関する Perl4 と Perl5 の違いの罠です。
Formatted output and significant digits@@@@@@@@@@書式指定された出力と最下位の数字
書式指定された出力と、最下位の数字。 一般的に Perl 5 はより的確に試します。 例えば、Solaris Sparc では:
print 7.373504 - 0, "\n";
printf "%20.18f\n", 7.373504 - 0;
# Perl4 prints:
7.3750399999999996141
7.375039999999999614
# Perl5 prints:
7.373504
7.373503999999999614
Perl 5 では、最初の結果がより良いものであることに注目してください。
あなたが実行した結果は違うかもしれません; あなたの浮動小数点フォーマット ルーチンや、そもそも浮動小数点フォーマットが少し違うかもしれないからです。
Auto-increment operator over signed int limit deleted@@@@@@@@@@符号付き整数の限界を超えたオートインクリメント演算子は削除されました
ここに記述されていた項目は削除されました。 以前あったものでは、オートインクリメント演算子が符号付き整数の限界を越えたことを 検知しないということを紹介していました。 これはバージョン 5.003_04 で修正されました。 が、大きな整数を取り扱うときには常に警戒してください。 不安を感じているのであれば:
use Math::BigInt;
Assignment of return values from numeric equality tests doesn't work@@@@@@@@@@数値の等価性の比較の結果を代入は正しく動作しません
数値の等価性の比較の結果を代入しても、perl ではその比較の結果が 偽 (0) であったときにはうまくいきません。 論理比較は、現在 0 ではなく null を返します。
$p = ($test == 1);
print $p,"\n";
# perl4 prints: 0
# perl5 prints:
この新しい仕様の別の例は "//, etc."" in "General Regular Expression Traps using s を参照してください。
Bitwise string ops@@@@@@@@@@ビット単位文字列演算子
数値としても文字列としても操作可能なビット操作演算子 (& | ^ ~
) が 文字列のみを引数として与えられた場合、 perl4 は、プログラムが vec()
関数の呼び出しを含んでいればオペランドを ビット文字列として扱います。 perl5 は文字列オペランドをビット文字列として扱います。 (さらなる詳細については "Bitwise String Operators" in perlop を 参照してください。)
$fred = "10";
$barney = "12";
$betty = $fred & $barney;
print "$betty\n";
# Uncomment the next line to change perl4's behavior
# ($dummy) = vec("dummy", 0, 0);
# Perl4 prints:
8
# Perl5 prints:
10
# If vec() is used anywhere in the program, both print:
10
ほとんどのデータ型と、それらの特定の表現やコンテキストでの 使い方に関する Perl4 と Perl5 の違いの罠です。
Negative array subscripts now count from the end of array@@@@@@@@@@配列の添え字が負であったとき配列の終端から数えられるようになりました
配列の添え字が負であったとき、それは配列の終端から数えられるように なりました。
@a = (1, 2, 3, 4, 5);
print "The third element of the array is $a[3] also expressed as $a[-2] \n";
# perl4 prints: The third element of the array is 4 also expressed as
# perl5 prints: The third element of the array is 4 also expressed as 4
Setting $#array
lower now discards array elements@@@@@@@@@@$#array
により小さな値を設定すると配列要素が捨てられるようになりました
$#array
に(それまでよりも)小さな値を設定したときには、余計な 配列要素は捨てられ、さらにそれが元に戻せないようになりました。
@a = (a,b,c,d,e);
print "Before: ",join('',@a);
$#a =1;
print ", After: ",join('',@a);
$#a =3;
print ", Recovered: ",join('',@a),"\n";
# perl4 prints: Before: abcde, After: ab, Recovered: abcd
# perl5 prints: Before: abcde, After: ab, Recovered: ab
Hashes get defined before use@@@@@@@@@@ハッシュは使われる前に定義されます
ハッシュは使われる前に定義されます。
local($s,@a,%h);
die "scalar \$s defined" if defined($s);
die "array \@a defined" if defined(@a);
die "hash \%h defined" if defined(%h);
# perl4 prints:
# perl5 dies: hash %h defined
Perl は defined(@a) と defined(%h) に警告を出すようになりました。
Glob assignment from localized variable to variable@@@@@@@@@@ある変数から別の変数へのグロブの代入
ある変数から別の変数へのグロブの代入は、 代入された変数が代入の後で局所化されているときには 失敗します。
@a = ("This is Perl 4");
*b = *a;
local(@a);
print @b,"\n";
# perl4 prints: This is Perl 4
# perl5 prints:
Assigning undef
to glob@@@@@@@@@@undef
のグロブへの代入
undef
のグロブへの代入は Perl 5 では何の影響も及ぼしません。 Perl 4 では結び付けられたスカラを undefine します (しかし SEGV を含め、なんらかの副作用があるかもしれません)。 Perl 5 はまた型グロブに undef
を代入すると警告されます。 (型グロブに undef
を代入するのは、型グロブに対して undef
関数を呼び出すのとは違います; いくつかの効果があります。)
$foo = "bar";
*foo = undef;
print $foo;
# perl4 prints:
# perl4 warns: "Use of uninitialized variable" if using -w
# perl5 prints: bar
# perl5 warns: "Undefined value assigned to typeglob" if using -w
Changes in unary negation (of strings)@@@@@@@@@@(文字列に対する)単項の符号反転の意味が変わりました
(文字列に対する)単項の符号反転の意味が変わりました。 この変更は戻り値と、マジックインクリメントの両方に影響します。
$x = "aaa";
print ++$x," : ";
print -$x," : ";
print ++$x,"\n";
# perl4 prints: aab : -0 : 1
# perl5 prints: aab : -aab : aac
Modifying of constants prohibited@@@@@@@@@@定数の修正は禁止されました
perl4 では定数を変更してしまいます。
$foo = "x";
&mod($foo);
for ($x = 0; $x < 3; $x++) {
&mod("a");
}
sub mod {
print "before: $_[0]";
$_[0] = "m";
print " after: $_[0]\n";
}
# perl4:
# before: x after: m
# before: a after: m
# before: m after: m
# before: m after: m
# Perl5:
# before: x after: m
# Modification of a read-only value attempted at foo.pl line 12.
# before: a
defined $var
behavior changed@@@@@@@@@@defined $var
の振る舞いは変わりました
perl4 と perl5 とで全然違う動作:
print "$x", defined $x
# perl 4: 1
# perl 5: <no output, $x is not called into existence>
Variable Suicide@@@@@@@@@@変数の自殺
perl5 では、変数の自殺(variable sucide)の振る舞いはより 首尾一貫したものとなりました。 perl4 ではスカラのみがそうであるような振る舞いを、 perl5 ではハッシュとスカラで示します。
$aGlobal{ "aKey" } = "global value";
print "MAIN:", $aGlobal{"aKey"}, "\n";
$GlobalLevel = 0;
&test( *aGlobal );
sub test {
local( *theArgument ) = @_;
local( %aNewLocal ); # perl 4 != 5.001l,m
$aNewLocal{"aKey"} = "this should never appear";
print "SUB: ", $theArgument{"aKey"}, "\n";
$aNewLocal{"aKey"} = "level $GlobalLevel"; # what should print
$GlobalLevel++;
if( $GlobalLevel<4 ) {
&test( *aNewLocal );
}
}
# Perl4:
# MAIN:global value
# SUB: global value
# SUB: level 0
# SUB: level 1
# SUB: level 2
# Perl5:
# MAIN:global value
# SUB: global value
# SUB: this should never appear
# SUB: this should never appear
# SUB: this should never appear
Elements of argument lists for formats evaluated in list context@@@@@@@@@@フォーマットに対する引数リストの要素はリストコンテキストで評価されるようになりました
フォーマットに対する引数リストの要素は、リストコンテキストで 評価されるようになりました。 これは、今やリストの値が 展開できるようになったということです。
@fmt = ("foo","bar","baz");
format STDOUT=
@<<<<< @||||| @>>>>>
@fmt;
.
write;
# perl4 errors: Please use commas to separate fields in file
# perl5 prints: foo bar baz
caller()
returns false value in scalar context if no caller present@@@@@@@@@@caller()
関数は呼び出し元がなくスカラコンテキストで呼ばれた場合には偽を返します
caller()
関数は呼び出し元がなく、スカラコンテキストで呼ばれた 場合には偽を返すようになりました。 これによりライブラリファイルが (自分が)require されたのかを判断することができます。
caller() ? (print "You rang?\n") : (print "Got a 0\n");
# perl4 errors: There is no caller
# perl5 prints: Got a 0
Comma operator in scalar context gives scalar context to args@@@@@@@@@@スカラコンテキストにあるカンマ演算子はその引数に対してスカラコンテキストを与えます
スカラコンテキストにあるカンマ演算子は、その最後の引数に対して スカラコンテキストを与えるようになりました。 環境に依存して、前にある引数にスカラコンテキストか無効コンテキストを 与えます。
@y= ('a','b','c');
$x = (1, 2, @y);
print "x = $x\n";
# Perl4 prints: x = c # Interpolates array @y into the list
# Perl5 prints: x = 3 # Evaluates array @y in scalar context
sprintf()
prototyped as ($;@)
@@@@@@@@@@sprintf()
のプロトタイプは ($;@)
sprintf()
のプロトタイプは ($;@) なので、最初の引数は スカラコンテキストです。従って、配列を渡すと、 Perl 4 とは違っておそらくあなたの望まない結果になるでしょう。
@z = ('%s%s', 'foo', 'bar');
$x = sprintf(@z);
print $x;
# perl4 prints: foobar
# perl5 prints: 3
しかし、printf()
のほうは Perl 4 と同じように動きます:
@z = ('%s%s', 'foo', 'bar');
printf STDOUT (@z);
# perl4 prints: foobar
# perl5 prints: foobar
評価順序に関する Perl4 と Perl5 の違いの罠です。
Perl4 はほとんどの演算子で Perl5 と同じ優先順位を持っています。 しかし Perl4 では、ドキュメントとは少々異なるような 一貫性に欠けるものがあります。
LHS vs. RHS of any assignment operator@@@@@@@@@@代入演算子の LHS 対 RHS
左辺と右辺は両方とも演算子を取るようになりました。 LHS は perl4 では最初に、perl5 では 2 番目に評価されます; これは 部分式の副作用の関係に影響を与えることがあります。
@arr = ( 'left', 'right' );
$a{shift @arr} = shift @arr;
print join( ' ', keys %a );
# perl4 prints: left
# perl5 prints: right
Semantic errors introduced due to precedence
以下の例は、優先順位の関係で意味エラー(semantic error)となるようになりました。
@list = (1,2,3,4,5);
%map = ("a",1,"b",2,"c",3,"d",4);
$n = shift @list + 2; # first item in list plus 2
print "n is $n, ";
$m = keys %map + 2; # number of items in hash plus 2
print "m is $m\n";
# perl4 prints: n is 3, m is 6
# perl5 errors and fails to compile
Precedence of assignment operators same as the precedence of assignment@@@@@@@@@@代入演算子の優先順位は代入と同じ
代入演算子の優先順位は、代入と同じとなりました。 perl4 は間違って、この優先順位が関連演算子と同じものに なっています。このため、式の中にあるのと同じように括弧でくくらなければ ならなくなりました。
/foo/ ? ($a += 2) : ($a -= 2);
下のようにしてしまうと、
/foo/ ? $a += 2 : $a -= 2
これは以下のように間違って解析されてしまいます
(/foo/ ? $a += 2 : $a) -= 2;
その一方で、
$a += /foo/ ? 1 : 2;
これは C プログラマーが期待するであろう動作になりました。
open
requires parentheses around filehandle@@@@@@@@@@open
はファイルハンドルの周りにかっこが必要です
open FOO || die;
これはもはや正しくなくなりました。ここではファイルハンドルを 括弧で括る必要があります。さもなければ、perl5 はこういった文を そのデフォルトの優先順位のまま放っておきます(以下の例参照)。
open(FOO || die);
# perl4 opens or dies
# perl5 opens FOO, dying only if 'FOO' is false, i.e. never
$:
precedence over $::
gone@@@@@@@@@@$:
は $::
と同じ優先順位
perl4 は特殊変数 $:
の優先順位に、perl5 が $::
を main パッケージと みなすのと同じ優先順位を与えます。
$a = "x"; print "$::a";
# perl 4 prints: -:a
# perl 5 prints: x
Precedence of file test operators documented@@@@@@@@@@ファイルテスト演算子の優先順位が文書化
perl には、ファイルテスト演算子と代入演算子を組み合わせたときに 優先順位のバグがありました。したがって、Perl4 の優先順位テーブルでは -e $foo .= "q"
は ((-e $foo) .= "q")
と解釈すべきなのに実際には ((-e $foo) .= "q")
と解釈していました。 Perl5 ではドキュメントにある通りの優先順位です。
-e $foo .= "q"
# perl4 prints: no output
# perl5 prints: Can't modify -e in concatenation
keys
, each
, values
are regular named unary operators@@@@@@@@@@keys
, each
, values
は通常の名前付き単項演算子
perl4 では、key()、each()、values() はシングルハッシュに対する 特別に高い評価順序を持った演算子でした; しかし perl5 では、これらの演算子は 通常の名前付き単項演算子となりました。 ドキュメントにある通り、名前付き単項演算子は、+ - .
のような 数学演算子や連結演算子よりも低い優先順位を持っていますが、perl4 では + - .
よりも key() などのほうが強く演算対象と結び付いていたのです。 したがって、以下の例のようになります:
%foo = 1..10;
print keys %foo - 1
# perl4 prints: 4
# perl5 prints: Type of arg 1 to keys must be hash (not subtraction)
この perl4 の振る舞いは便利であるかもしれませんが、一貫性に欠けます。
正規表現に関する全てのタイプの罠。
s'$lhs'$rhs'
interpolates on either side
s'$lhs'$rhs'
はもはやいずれの辺にあっても展開されなくなりました。 以前は $lhs は展開し、$rhs を展開しませんでした。 (文字列にあるリテラルの '$' にはいまでもマッチしません)。
$a=1;$b=2;
$string = '1 2 $a $b';
$string =~ s'$a'$b';
print $string,"\n";
# perl4 prints: $b 2 $a $b
# perl5 prints: 1 2 $a $b
m//g
attaches its state to the searched string
m//g
は、その状態を正規表現ではなく検索対象の文字列に 結び付けるようになりました。 (sub に対するブロックのスコープが残っているのであれば、 検索文字列の状態は失われます)
$_ = "ababab";
while(m/ab/g){
&doit("blah");
}
sub doit{local($_) = shift; print "Got $_ "}
# perl4 prints: Got blah Got blah Got blah Got blah
# perl5 prints: infinite loop blah...
m//o
used within an anonymous sub
現在のところ、m//o
量指定子を無名サブルーチンの中にある正規表現で 使った場合、すべての クロージャーはそのような無名サブルーチンから、 そういったクロージャの中で一番最初に使われたものの中で コンパイルされたかのような正規表現を生成します。 例えば、以下のようにすると
sub build_match {
my($left,$right) = @_;
return sub { $_[0] =~ /$left stuff $right/o; };
}
$good = build_match('foo','bar');
$bad = build_match('baz','blarch');
print $good->('foo stuff bar') ? "ok\n" : "not ok\n";
print $bad->('baz stuff blarch') ? "ok\n" : "not ok\n";
print $bad->('foo stuff bar') ? "not ok\n" : "ok\n";
Perl5 のほとんどのビルドでは、これは以下のように出力します:
この例の場合、build_match() は常に最初
に build_match() が呼ばれたときの $left と $right の内容にマッチするようなサブルーチンを返します; 呼び出されたその時点での値ではありません。
$+
isn't set to whole match
マッチングの中で括弧が使われなかった場合、Perl4 では $+
には $&
と同じようにマッチした全体がセットされます。 Perl5 ではそうではありません。
"abcdef" =~ /b.*e/;
print "\$+ = $+\n";
# perl4 prints: bcde
# perl5 prints:
Substitution now returns null string if it fails
置換は、失敗したときには空文字列を返すようになりました。
$string = "test";
$value = ($string =~ s/foo//);
print $value, "\n";
# perl4 prints: 0
# perl5 prints:
この新しい仕様に関しては "Numerical Traps" も参照してください。
s`lhs`rhs`
is now a normal substitution
s`lhs`rhs`
(バッククォートの使用)は通常の置換となり、 バッククォートの展開は行われなくなりました。
$string = "";
$string =~ s`^`hostname`;
print $string, "\n";
# perl4 prints: <the local hostname>
# perl5 prints: hostname
Stricter parsing of variables in regular expressions
正規表現中の変数の使用に関する構文解析がより厳密になりました。
s/^([^$grpc]*$grpc[$opt$plus$rep]?)//o;
# perl4: compiles w/o error
# perl5: with Scalar found where operator expected ..., near "$opt$plus"
同じスクリプトでこの例に付け加えことは、置換後の文字列の実際の値です。 [$opt]
は perl4 ではキャラクタクラスであり、perl5 では配列の 添え字となります。
$grpc = 'a';
$opt = 'r';
$_ = 'bar';
s/^([^$grpc]*$grpc[$opt]?)/foo/;
print;
# perl4 prints: foo
# perl5 prints: foobar
m?x?
matches only once
perl5 では、m?x?
は ?x?
と同様に一回だけマッチします。 perl4 では、/x/
や m!x!
と同じように何度でもマッチします。
$test = "once";
sub match { $test =~ m?once?; }
&match();
if( &match() ) {
# m?x? matches more then once
print "perl4\n";
} else {
# m?x? matches only once
print "perl5\n";
}
# perl4 prints: perl4
# perl5 prints: perl5
Failed matches don't reset the match variables
Ruby と違って、Perl ではマッチングに失敗してもマッチング変数 ($1, $2, ..., $`
, ...) はリセットされません。
Perl4 と Perl5 の違いの罠に分類される一般的なものはシグナル、ソート、そして それらに関連するサブルーチンで、サブルーチンの罠と同じ様なものです。 いくつかの OS 固有の罠を含みます。
Barewords that used to look like strings look like subroutine calls
文字列のように見える裸の単語は、その名前が使うよりも前に サブルーチンの名前として定義されている場合にはサブルーチンとして みなされます。
sub SeeYa { warn"Hasta la vista, baby!" }
$SIG{'TERM'} = SeeYa;
print "SIGTERM is now $SIG{'TERM'}\n";
# perl4 prints: SIGTERM is now main'SeeYa
# perl5 prints: SIGTERM is now main::1 (and warns "Hasta la vista, baby!")
-w を使って、これを発見できます。
Reverse is no longer allowed as the name of a sort subroutine
reverse はもはやソートのサブルーチンの名前としては 使えなくなりました。
sub reverse{ print "yup "; $a <=> $b }
print sort reverse (2,1,3);
# perl4 prints: yup yup 123
# perl5 prints: 123
# perl5 warns (if using -w): Ambiguous call resolved as CORE::reverse()
warn()
won't let you specify a filehandle.
「常に」 STDERR に出力していたにもかかわらず、perl4 では warn() は ファイルハンドルの指定を必要としていました。 perl5 では必要なくなりました。
warn STDERR "Foo!";
# perl4 prints: Foo!
# perl5 prints: String found where operator expected
SysV resets signal handler correctly
HPUX 及び一部の SysV OS では、perl4 のときには シグナルが発生する度にそのシグナルハンドラ関数の中で シグナルハンドラを再設定しなければなりませんでした。 perl5 では、この再設定を正しく行うようになりました。 ハンドラを再設定しないということに依存したプログラムは 作業しなおす必要があります。
5.002 以降の perl では、SysV のときには sigaction() を使います。
sub gotit {
print "Got @_... ";
}
$SIG{'INT'} = 'gotit';
$| = 1;
$pid = fork;
if ($pid) {
kill('INT', $pid);
sleep(1);
kill('INT', $pid);
} else {
while (1) {sleep(10);}
}
# perl4 (HPUX) prints: Got INT...
# perl5 (HPUX) prints: Got INT... Got INT...
SysV seek()
appends correctly
SysV OS では、追記モード (>>
) でオープンしたファイルに対する seek()
は fopen() マニュアルページにあるように正しく動作するように なりました。 例えば、追記モードでファイルをオープンした場合には既にファイルにある情報を 上書きすることはできません。
open(TEST,">>seek.test");
$start = tell TEST;
foreach(1 .. 9){
print TEST "$_ ";
}
$end = tell TEST;
seek(TEST,$start,0);
print TEST "18 characters here";
# perl4 (solaris) seek.test has: 18 characters here
# perl5 (solaris) seek.test has: 1 2 3 4 5 6 7 8 9 18 characters here
Perl4 と Perl5 の違いの罠には、式や文、コンテキストなどにおける 展開に関するものがあります。
@
always interpolates an array in double-quotish strings
ダブルクォートで囲まれた文字列にある @ は常に配列に展開されます。
print "To: someone@somewhere.com\n";
# perl4 prints: To:someone@somewhere.com
# perl < 5.6.1, error : In string, @somewhere now must be written as \@somewhere
# perl >= 5.6.1, warning : Possible unintended interpolation of @somewhere in string
Double-quoted strings may no longer end with an unescaped $
ダブルクォートで括られた文字列がエスケープされていない $ で 終了することがなくなりました。
$foo = "foo$";
print "foo is $foo\n";
# perl4 prints: foo is foo$
# perl5 errors: Final $ should be \$ or $name
注意: perl5 は、$bar の終端にある @ については“エラーにしません”
Arbitrary expressions are evaluated inside braces within double quotes
Perl はダブルクォート中にあるブレースの内側の任意の式を 評価するようになりました(一般的には、$
や @
に続いて 開きのブレースがきたときです)。
@www = "buz";
$foo = "foo";
$bar = "bar";
sub foo { return "bar" };
print "|@{w.w.w}|${main'foo}|";
# perl4 prints: |@{w.w.w}|foo|
# perl5 prints: |buz|bar|
use strict;
を使って、perl5 におけるこのような罠を避けることが できることに注意してください。
$$x
now tries to dereference $x
"this is $$x" はプロセス ID を展開するようになっていましたが、 今は $x の参照外し(dereference)を試みます。 それでも $$
自身は今でもきちんと動作します。
$s = "a reference";
$x = *s;
print "this is $$x\n";
# perl4 prints: this is XXXx (XXX is the current pid)
# perl5 prints: this is a reference
Creation of hashes on the fly with eval "EXPR"
requires protection
eval "EXPR"
を使ったその場(on the fly)でのハッシュの生成は ハッシュの名前を指定する $
がプロテクトされているか、もしくは 両方の中かっこがプロテクトされていることを要求します。 両方の中かっこがプロテクトされている場合には、perl4 と perl5 の結果は同じです。 これはとても一般的な慣習で、もし可能ならブロック形式の eval{}
を 使うように変更するべきです。
$hashname = "foobar";
$key = "baz";
$value = 1234;
eval "\$$hashname{'$key'} = q|$value|";
(defined($foobar{'baz'})) ? (print "Yup") : (print "Nope");
# perl4 prints: Yup
# perl5 prints: Nope
以下のものを変更します:
eval "\$$hashname{'$key'} = q|$value|";
このように:
eval "\$\$hashname{'$key'} = q|$value|";
結果はこうなります:
# perl4 prints: Nope
# perl5 prints: Yup
以下のように変更した場合には
eval "\$$hashname\{'$key'\} = q|$value|";
結果はこうなります:
# perl4 prints: Yup
# perl5 prints: Yup
# and is compatible for both versions
Bugs in earlier perl versions
以前のバージョンにあったバグに依存しているような perl4 プログラム。
perl -e '$bar=q/not/; print "This is $foo{$bar} perl5"'
# perl4 prints: This is not perl5
# perl5 prints: This is perl5
Array and hash brackets during interpolation
展開中の配列とハッシュの大かっこについても注意する必要があります。
print "$foo["
perl 4 prints: [
perl 5 prints: syntax error
print "$foo{"
perl 4 prints: {
perl 5 prints: syntax error
Perl 5 は、個々のかっこには添え字かキー名が続き、さらに適切な種類の 閉じかっこが続くと仮定しています。 Perl 4 の振る舞いを模倣するためには、そのようなかっこを エスケープしなければなりません。
print "$foo\[";
print "$foo\{";
Interpolation of \$$foo{bar}
同様に、\$$foo{bar}
にも注意してください:
$foo = "baz";
print "\$$foo{bar}\n";
# perl4 prints: $baz{bar}
# perl5 prints: $
perl5 は存在しない $foo{bar}
を探しに行きますが、perl4 は $foo を“baz”に展開しただけで満足します。 eval
でもこの事に注意してください。
qq()
string passed to eval
will not find string terminator
eval
に qq()
された文字列を渡した場合
eval qq(
foreach \$y (keys %\$x\) {
\$count++;
}
);
# perl4 runs this ok
# perl5 prints: Can't find string terminator ")"
DBMに関する一般的な罠。
Perl5 must have been linked with same dbm/ndbm as the default for dbmopen()
perl4 で(もしくは他の dbm/ndbm ツールで)作成した dbm データベースを、 perl5 の元で同じスクリプトで扱おうとすると失敗します。 perl5 の作成において、拡張 dbm の実装を tie
しないときに dbmopen()
がデフォルトで使用する関数のために (perl4 のときと同じ)同じ dbm/ndbm をリンクしていなければなりません。
dbmopen (%dbm, "file", undef);
print "ok\n";
# perl4 prints: ok
# perl5 prints: ok (IFF linked with -ldbm or -lndbm)
DBM exceeding limit on the key/value size will cause perl5 to exit immediately
perl4 で(もしくは他の dbm/ndbm ツールで)作成した dbm データベースを、 perl5 の元で同じスクリプトで扱おうとすると失敗します。 key/value のサイズに関する制限を超えたときに発生するエラーにより、 perl5 では即座にプログラムから exit します。
dbmopen(DB, "testdb",0600) || die "couldn't open db! $!";
$DB{'trap'} = "x" x 1024; # value too large for most dbm/ndbm
print "YUP\n";
# perl4 prints:
dbm store returned -1, errno 28, key "trap" at - line 3.
YUP
# perl5 prints:
dbm store returned -1, errno 28, key "trap" at - line 3.
その他の罠。
require
/do
trap using returned value@@@@@@@@@@require
/do
の戻り値を使ったときの罠
doit.pl というファイルが
sub foo {
$rc = do "./do.pl";
return 8;
}
print &foo, "\n";
であって、do.pl が以下のような内容だったとすると、
return 3;
doit.pl の実行結果はこうなります。
# perl 4 prints: 3 (aborts the subroutine early)
# perl 5 prints: 8
do
を require
に置き換えても同じ振る舞いとなります。
split
on empty string with LIMIT specified@@@@@@@@@@空文字列に LIMIT を指定して split
を使った場合
$string = '';
@list = split(/foo/, $string, 2)
Perl4 は空文字列を持った一要素のリストを返しますが、Perl5 は 空リストを返します。
いつものように、バグとして公式に宣言されたものがあれば、 それは修正されて取り除かれるでしょう。