18

我正在寻找有关 Perl 最佳实践的建议。我写了一个脚本,它有一个复杂的正则表达式:

my $regex = qr/complicated/;

# ...

sub foo {
  # ...

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

wherefoo是一个经常被调用的函数,并且$regex不在该函数之外使用。处理这种情况的最佳方法是什么?我只希望它被解释一次,因为它又长又复杂。但是将它放在全局范围内似乎有点问题,因为它只在那个子中使用。有没有一种合理的方式来声明它是静态的?

另一个可能不合理的全球也出现了类似的问题。它读入当前的日期和时间并对其进行适当的格式化。这也被多次使用,而且只在一个功能中使用。但在这种情况下,更重要的是不要重新初始化它,因为我希望日期时间的所有实例在给定的脚本调用中都是相同的,即使在执行期间分钟翻转。

目前我有类似的东西

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一次。

如果您需要使用较旧的 perls,请在外部范围内使用带有额外大括号的词法变量:

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

这可以$foo防止泄漏给除womble.

于 2012-05-31T20:55:05.757 回答
16

模式中有插值吗?如果没有,无论 qr// 执行多少次,模式都只会编译一次。

$ 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

正则表达式可以用“o”修饰符指定,它表示“只编译一次模式”——在第三个。骆驼版,见 p. 147

于 2014-07-02T16:25:27.130 回答
1

我想完成ikegami的好答案。我想在 5.10 之前的局部变量的定义上浪费更多的话。

让我们看一个简单的示例代码:

#!/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会打印在第三行)

这可以很容易地解决:

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

现在的输出是预期的:

After Crying
Solaris

state在 5.10+ 中是更好的选择...

我希望这有帮助!

于 2015-01-23T10:14:12.350 回答
1

有一个state关键字可能非常适合这种情况:

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