考虑以下Perl代码。
#!/usr/bin/perl
use strict;
use warnings;
$b="1";
my $a="${b}";
$b="2";
print $a;
该脚本显然会输出1
。我希望它是$b
的当前值。
Perl中最聪明的方法是如何实现这样的懒惰评估?我希望${b}
保持“未替代”,直到需要$a
。
答案 0 :(得分:15)
我更想知道你为什么要这样做。根据您真正需要做的事情,您可以使用各种方法。
您可以将代码包装在coderef中,并仅在需要时对其进行评估:
use strict; use warnings;
my $b = '1';
my $a = sub { $b };
$b = '2';
print $a->();
这种方法的一个变体是使用命名函数作为closure(这可能是最好的方法,在你的调用代码的更大的上下文中):
my $b = '1';
sub print_b
{
print $b;
}
$b = '2';
print_b();
您可以使用对原始变量的引用,并根据需要取消引用它:
my $b = '1';
my $a = \$b;
$b = '2';
print $$a;
答案 1 :(得分:4)
Perl将在代码运行时插入一个字符串,我不知道如何使它不这样做,缺少格式(这是丑陋的IMO)。但是,你可以做的是将“当代码运行时”更改为更方便的东西,方法是将字符串包装在sub中并在需要插入字符串时调用它...
$b = "1";
my $a = sub { "\$b is $b" };
$b = "2";
print &$a;
或者,你可以做一些eval魔法,但它更具侵入性(你需要对字符串进行一些操作才能实现它)。
答案 2 :(得分:3)
你想要的不是懒惰评估,而是后期绑定。要在Perl中获取它,您需要使用eval
。
my $number = 3;
my $val = "";
my $x = '$val="${number}"';
$number = 42;
eval $x;
print "val is now $val\n";
请注意,eval
通常效率低,而且有条不紊。使用其他答案之一的解决方案几乎肯定会更好。
答案 3 :(得分:3)
正如其他人所提到的,Perl只会在使用eval
编写字符串时在运行时调用编译器来评估字符串。您可以使用其他答案中指出的引用,但这会改变代码的外观($$a
vs $a
)。但是,这是Perl,有一种方法可以使用tie
隐藏简单变量背后的高级功能。
{package Lazy;
sub TIESCALAR {bless \$_[1]} # store a reference to $b
sub FETCH {${$_[0]}} # dereference $b
sub STORE {${$_[0]} = $_[1]} # dereference $b and assign to it
sub new {tie $_[1] => $_[0], $_[2]} # syntactic sugar
}
my $b = 1;
Lazy->new( my $a => $b ); # '=>' or ',' but not '='
print "$a\n"; # prints 1
$b = 2;
print "$a\n"; # prints 2
您可以查找tie
的文档,但简而言之,它允许您定义自己的变量实现(对于标量,数组,散列或文件句柄)。因此,此代码创建新变量$a
,其实现可获取或设置$b
的当前值(通过在内部存储对$b
的引用)。 new
方法不是严格需要的(构造函数实际上是TIESCALAR
),但是作为语法糖提供,以避免在调用代码中直接使用tie
。
(这将是tie my $a, 'Lazy', $b;
)
答案 4 :(得分:1)
你希望假装$ a指的是在使用$ a时评估的东西...你只能在$ a不是真正的标量时才这样做,它可以是一个函数(如cHao的答案)或者,在这个简单的例子中,引用了另一个变量
my $b="1";
my $a= \$b;
$b="2";
print $$a;
答案 5 :(得分:1)
我希望$ {b}保持“未替代”,直到需要$ a。
然后我建议避免使用字符串插值,而是使用sprintf
,以便在需要时“插入”。
当然,在此基础上你可以tie
快速(ish)和肮脏的东西:
use strict;
use warnings;
package LazySprintf;
# oh, yuck
sub TIESCALAR { my $class = shift; bless \@_, $class; }
sub FETCH { my $self = shift; sprintf $self->[0], @$self[1..$#$self]; }
package main;
my $var = "foo";
tie my $lazy, 'LazySprintf', '%s', $var;
print "$lazy\n"; # prints "foo\n"
$var = "bar";
print "$lazy\n"; # prints "bar\n";
也适用于更具异国情调的格式说明符。呸。