速度 - perl 配列 検索 高速
Perlの一般的な問題? (20)
Perlの隠された特徴に関する質問は、特徴か誤った特徴のいずれかとみなすことができる少なくとも1つの応答をもたらした。 この質問をフォローアップすることは理にかなっていたようです。Perlでよく見られる間違いは何ですか? 彼らは仕事をしなければならないように見えるが、しないように見えるもの。
私は答えを構造化する方法や、あまりにも簡単なことを勘違いとみなすことについてのガイドラインを提示しません。なぜなら、それが投票のためだからです。
回答の一覧
構文
- 一般
- ファイルハンドル
セマンティクス/言語機能
- 一般
- コンテキスト
- 変数
デバッグ
ベストプラクティス
-
use strict
use warnings
use strict
忘れる(またはuse diagnostics
) - 変数名が間違っています (つまり
use strict
)
メタアンサー
関連項目: ASP.NET - よくある問題
"私の"宣言は変数のリストの周りにかっこを使うべきです
use strict;
my $a = 1;
mysub();
print "a is $a\n";
sub {
my $b, $a; # Gotcha!
$a = 2;
}
my
宣言は$b
しか適用されなかったので、 aは2です(その行の$a
には何もしませんでした)。 これは、 "use strict"が有効であっても、警告なしに発生することに注意してください。
"use warnings"(または-wフラグ)を追加すると、 "my"リストの周りに括弧がないことをPerlが大きく改善します 。 これは、多くの人が既に行っているように、厳密な警告と警告の両方のプラグマが常に良いアイデアである理由を示しています。
連結の初期化されていない値の使用...
これは私を狂ってしまう。 あなたは、以下のようないくつかの変数を含むプリントを持っています。
print "$label: $field1, $field2, $field3\n";
変数の1つはundefです。 あなたはこれをあなたのプログラムのバグとみなします。そのため、あなたは "strict"プラグマを使用していたのです。 おそらくデータベーススキーマが期待していないフィールドでNULLを許可しているか、変数の初期化などを忘れていたかもしれませんが、連結エラー( .
)操作中に初期化されていない値が見つかったというエラーメッセージが表示されます。 もしそれが初期化されていない変数の名前をあなたに伝えたら!
Perlは何らかの理由でエラーメッセージに変数名を表示したくないので、ブレークポイントを設定して( undefのどの変数を調べるか)、条件をチェックするコードを追加することで、変数名を追跡してしまいます。 非常に厄介なのは、CGIスクリプトの中で数千回しか起こらず、簡単に再作成することができないときです。
Graeme Perrowの答えは良かったけど、それはさらに良くなった!
リストコンテキストで素敵なリストを返す典型的な関数が与えられたら、スカラーコンテキストではどうなるでしょうか? (「典型的」とは、ドキュメンテーションが言うことのない一般的なケースを意味し、私たちはそれが貴方の書いた機能かもしれません。
sub f { return ('a', 'b', 'c'); }
sub g { my @x = ('a', 'b', 'c'); return @x; }
my $x = f(); # $x is now 'c'
my $y = g(); # $y is now 3
関数が呼び出されるコンテキストは、その関数内のステートメントをreturn
伝播されます。
呼び出し元は、コードの振る舞いについて効率的な推論を可能にする簡単な経験則を望むのは間違っていたと思います 。 そうです、Perl、 呼び出された関数のソースコードを呼び出すたびに 、呼び出し元のキャラクタがうまくいきます。
perltrapマンページには、タイプ別の不注意なトラップが多数リストされています。
変数名の間違い... Perlのエラーではなく、新しい変数の宣言である変数名に誤字を見つけるためにのみ正しく動作するわけではないトラブルシューティングコード全体を午後一回過ごしました。
あなたがそうするのが愚かであれば、Perlは同じ名前の複数の変数を宣言することができます:
my ($x, @x, %x);
Perlは変数型ではなくコンテキストを識別するためにsigilsを使用しているため、特に$x
が参照の場合は、後のコードで変数を使用するときに混乱が生じます。
$x[0]
$x{key}
$x->[0]
$x->{key}
@x[0,1]
@x{'foo', 'bar'}
@$x[0,1]
@$x{'foo', 'bar'}
...
この問題はPerl 5.10で修正されています - あなたが幸運であれば、アップグレードするためのアレルギーではない場所で作業することができます:>-(
私は変数「それはゼロになる」と話します。 あなたは、次のような句で予期しない結果を引き起こすものを知っています:
unless ($x) { ... }
$x ||= do { ... };
Perl 5.10には、// =または定義済みまたは演算子があります。
これは、コードが生産に入る前にテストでは考慮されていないエッジ条件によって有効なゼロが発生したときに、特に陰謀です...
これはメタアナリシスです。 perlcritic
コマンドを使ってコマンドラインからインストールして実行できるPerl::Critic 、たくさんの厄介な問題を発見しました。(インターネット上でコードを送信して、オプション)をPerl :: CriticのWebサイトから入手できます。
Perl::Critic
は、ページ番号を含むDamian Conways Perlベストプラクティスブックへの参照を提供します。 Perl::Critic
は、あなたが読んでいなければならないビットをまだ伝えることができます。
どのようにその事実について
@array = split( / /, $string );
同じ結果を与えない
@array = split( ' ', $string );
$ stringに先行スペースがある場合は?
それはいくつかの人々を驚かせるかもしれない。
ほとんどのPerlのループ演算子( foreach
、 map
、 grep
)は自動的に$_
ローカライズしますが、 while(<FH>)
はそうではありません。 これは、遠く離れた奇妙な行動につながります。
ハッシュの "コンストラクタ"はリスト以上のもので、 =>
太いコンマは構文的な砂糖にすぎません。 []
arrayref構文と()
リストの構文を混同すると、これによって噛まれることがあります:
my %var = (
("bar", "baz"),
fred => "barney",
foo => (42, 95, 22)
);
# result
{ 'bar' => 'baz',
'95' => 22,
'foo' => 42,
'fred' => 'barney' };
# wanted
{ 'foo' => [ 42, 95, 22 ] }
ループしている配列をfor(each)で次のように変更します:
my @array = qw/a b c d e f g h/;
for ( @array ) {
my $val = shift @array;
print $val, "\n";
}
それは混乱し、あなたが期待することをしません
単項マイナス"foo"
は"-foo"
作成します:
perl -le 'print -"foo" eq "-foo" ? "true" : "false"'
これは最初の文字が/[_a-zA-Z]/
一致する場合にのみ機能します。 最初の文字が"-"
場合は、最初の文字を"+"
に変更し、最初の文字が"+"
場合は、最初の文字を"-"
ます。 最初の文字が/[^-+_a-zA-Z]/
一致する場合、文字列を数値に変換してその結果を否定します。
perl -le '
print -"foo";
print -"-foo";
print -"+foo";
print -"\x{e9}"; #e acute is not in the accepted range
print -"5foo"; #same thing for 5
'
上のコードは印刷しています
-foo
+foo
-foo
-0
-5
この機能は、ほとんどの場合、人々が
my %options = (
-depth => 5,
-width => 2,
-height => 3,
);
型グロブ全体をエクスポートしない限り、エクスポートされた変数をローカライズすることはできません。
定数は再定義できます。 誤って定数を再定義する簡単な方法は、定数を参照として定義することです。
use constant FOO => { bar => 1 };
...
my $hash = FOO;
...
$hash->{bar} = 2;
今、FOOは{bar => 2}です。
mod_perl(少なくとも1.3以降)を使用している場合、新しいFOO値はモジュールがリフレッシュされるまで保持されます。
最も一般的な問題は、ファイルを別のもので起動することです。
use strict;
use diagnostics;
pjfは次のように付け加えています:診断はパフォーマンスに重大な影響を与えることに注意してください。 perldiag.podをロードする必要があるため、プログラムの起動が遅くなり、数週間前のbleadperlまで、$&を使用するため正規表現が遅くなります。 警告を使用し、結果にsplain
を実行することをお勧めします。
混乱する参照と実際のオブジェクト:
$a = [1,2,3,4];
print $a[0];
( $a->[0]
(最高)、 $$a[0]
、 @{$a}[0]
または@$a[0]
いずれかでなければなりません)
私はこれを一度やった:
my $object = new Some::Random::Class->new;
エラーを見つけるために年を取った。 間接メソッド構文はeeevilです。
配列をスカラーに割り当てることは私には意味がありません。 例えば:
$foo = ( 'a', 'b', 'c' );
$ fooに 'c'を代入し、配列の残りの部分を取り除きます。 これはより奇妙です:
@foo = ( 'a', 'b', 'c' );
$foo = @foo;
これは、最初の例と同じことをする必要があるようですが、代わりに$foo
を@foo
の長さに@foo
するので、 $foo == 3
ます。
my $x = <>;
do {
next if $x !~ /TODO\s*[:-]/;
...
} while ( $x );
do
はループではありません。 next
はできません。 これはブロックを実行するための命令です。 それは次のようなものです
$inc++ while <>;
それにもかかわらず、それはC言語の言語の構築のように見えます。