18

Perlのベストプラクティスに関するアドバイスを探しています。複雑な正規表現を持つスクリプトを作成しました。

my $regex = qr/complicated/;

# ...

sub foo {
  # ...

  if (/$regex/)
  # ...
}

ここfooで、は頻繁に呼び出される関数であり、$regexその関数の外部では使用されません。このような状況を処理するための最良の方法は何ですか?長くて複雑なので、一度だけ解釈してほしい。ただし、そのサブでのみ使用されるため、グローバルスコープで使用するのは少し疑わしいようです。それを静的と宣言する合理的な方法はありますか?

同様の問題は、正当化されていない可能性のある別のグローバルでも発生します。現在の日時を読み取り、適切にフォーマットします。これも何度も使用され、1つの機能でのみ使用されます。ただし、この場合、実行中に分がロールオーバーした場合でも、スクリプトの特定の呼び出しから日時のすべてのインスタンスを同じにしたいので、再初期化しないことがさらに重要です。

現時点で私は次のようなものを持っています

my ($regex, $DT);

sub driver {
  $regex = qr/complicated/;
  $DT = dateTime();
  # ...
}

# ...

driver();

これは少なくともわずかにそれを分離します。しかし、おそらくもっと良い方法があります。

繰り返しますが、ベストプラクティスとPerlイディオムに従うという観点から、これを行う正しい方法を探しています。パフォーマンスは素晴らしいですが、すべてを手に入れることができない場合は、読みやすさやその他のニーズが優先されます。

4

5 に答える 5

29

perl 5.10+を使用している場合は、state変数を使用してください。

use feature 'state';
# use 5.010; also works

sub womble {
    state $foo = something_expensive();
    return $foo ** 2;
}

一度だけ呼び出しますsomething_expensive

古いperlを使用する必要がある場合は、外側のスコープで中括弧のペアを追加して字句変数を使用します。

{
    my $foo = something_expensive();
    sub womble {
        return $foo ** 2;
    }
}

これ$fooにより、を除く誰にもリークすることがなくなりwombleます。

于 2012-05-31T20:55:05.757 に答える
16

パターンに補間はありますか?そうでない場合、qr //が何回実行されても、パターンは1回だけコンパイルされます。

$ perl -Mre=debug -e'qr/foo/ for 1..10' 2>&1 | grep Compiling | wc -l
1

$ perl -Mre=debug -e'qr/foo$_/ for 1..10' 2>&1 | grep Compiling | wc -l
10

補間がある場合でも、補間された変数が変更された場合にのみパターンがコンパイルされます。

$ perl -Mre=debug -e'$x=123; qr/foo$x/ for 1..10;' 2>&1 | grep Compiling | wc -l
1

$ perl -Mre=debug -e'qr/foo$_/ for 1..10' 2>&1 | grep Compiling | wc -l
10

それ以外の場合は、

{
   my $re = qr/.../;
   sub foo {
      ...
      /$re/
      ...
   }
}

また

use feature qw( state );
sub foo {
   state $re = qr/.../;
   ...
   /$re/
   ...
}
于 2012-05-31T21:14:04.703 に答える
4

正規表現は、3番目に「パターンを1回だけコンパイルする」という「o」修飾子を使用して指定できます。キャメルのエディション、pを参照してください。147

于 2014-07-02T16:25:27.130 に答える
1

この状況に適している可能性のあるstateキーワードがあります。

sub foo {
    state $regex = /.../;
    ...
}
于 2012-05-31T20:53:14.773 に答える
1

ikegamiの素晴らしい答えを完成させたいと思います。でのローカル変数の定義についてもう少し無駄にしたいと思います。

簡単なサンプルコードを見てみましょう。

#!/bin/env perl 

use strict;
use warnings;

{ # local 
my $local = "After Crying";
sub show { print $local,"\n"; }
} # local

sub show2;

show;
show2;

exit;

{ # local 
my $local = "Solaris";
sub show2 { print $local,"\n"; }
} # local

subユーザーは両方がローカル変数を出力することを期待しますが、これは真実ではありません!

出力:

After Crying
Use of uninitialized value $local in print at ./x.pl line 20.

その理由は、show2解析されますが、ローカル変数の初期化が実行されないためです。(もちろん、exit削除show2して最後にaを追加するとSolaris、3行目に印刷されます)

これは簡単に修正できます。

{ # local 
my $local;
BEGIN { $local = "Solaris"; }
sub show2 { print $local,"\n"; }
} # local

そして今、期待されたものを出力します:

After Crying
Solaris

しかしstate、5.10+ではより良い選択です...

これがお役に立てば幸いです。

于 2015-01-23T10:14:12.350 に答える