Perl中的静态局部变量

时间:2012-05-31 20:50:19

标签: perl scope

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

my $regex = qr/complicated/;

# ...

sub foo {
  # ...

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

其中foo是一个经常调用的函数,$regex不在该函数之外使用。处理这种情况的最佳方法是什么?我只希望它被解释一次,因为它漫长而复杂。但是将它放在全球范围内似乎有点可疑,因为它仅用于该子目录。是否有合理的方式将其声明为静态?

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

目前我有类似

的东西
my ($regex, $DT);

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

# ...

driver();

至少稍微隔离它。但也许有更好的方法。

再次说明:我正在寻找正确的方法,以遵循最佳实践和Perl习语。性能很好,但如果我不能拥有所有东西,那么可读性和其他需求就会优先考虑。

5 个答案:

答案 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 之前,我想浪费一些关于局部变量定义的词。

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

#!/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是更好的选择......

我希望这有帮助!