我正在寻找有关Perl最佳实践的建议。我写了一个脚本,它有一个复杂的正则表达式:
my $regex = qr/complicated/;
# ...
sub foo {
# ...
if (/$regex/)
# ...
}
其中foo
是一个经常调用的函数,$regex
不在该函数之外使用。处理这种情况的最佳方法是什么?我只希望它被解释一次,因为它漫长而复杂。但是将它放在全球范围内似乎有点可疑,因为它仅用于该子目录。是否有合理的方式将其声明为静态?
另一个可能不合理的全球性问题也出现了类似的问题。它读取当前日期和时间并适当地格式化它。这也被多次使用,并且仅在一个功能中使用。但在这种情况下,更重要的是不要重新初始化,因为我希望日期时间的所有实例在给定的脚本调用中都是相同的,即使在执行期间分钟翻转也是如此。
目前我有类似
的东西my ($regex, $DT);
sub driver {
$regex = qr/complicated/;
$DT = dateTime();
# ...
}
# ...
driver();
至少稍微隔离它。但也许有更好的方法。
再次说明:我正在寻找正确的方法,以遵循最佳实践和Perl习语。性能很好,但如果我不能拥有所有东西,那么可读性和其他需求就会优先考虑。
答案 0 :(得分:25)
如果您使用的是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
以外的任何人。
答案 1 :(得分:15)
模式中是否有插值?如果不是,则无论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/
...
}
答案 2 :(得分:4)
可以使用“o”修饰符指定正则表达式,该修饰符在第3个中表示“仅编译一次模式”。骆驼版,见第147
答案 3 :(得分:1)
有一个state关键字可能非常适合这种情况:
sub foo {
state $regex = /.../;
...
}
答案 4 :(得分:1)
我想完成ikegami
的好答案。在5.10 perl之前,我想浪费一些关于局部变量定义的词。
让我们看一个简单的示例代码:
#!/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
,则会在第三行显示Solaris
这很容易解决:
{ # local
my $local;
BEGIN { $local = "Solaris"; }
sub show2 { print $local,"\n"; }
} # local
现在的输出是预期的:
After Crying
Solaris
但5.10+中的state
是更好的选择......
我希望这有帮助!