[英]Perl, evaluate string lazily
考慮下面的Perl代碼。
#!/usr/bin/perl
use strict;
use warnings;
$b="1";
my $a="${b}";
$b="2";
print $a;
該腳本顯然輸出1
。 我希望它是$b
當前的值。
在Perl中實現這種惰性評估的最聰明的方法是什么? 我希望${b}
在需要$a
之前保持“不變”。
我對知道為什么要這樣做感興趣。 您可以根據實際需要使用多種方法。
您可以將代碼包裝在coderef中,並僅在需要時對其進行評估:
use strict; use warnings;
my $b = '1';
my $a = sub { $b };
$b = '2';
print $a->();
這種方法的一種變體是使用命名函數作為閉包 (在調用代碼的較大上下文中,這可能是最好的方法):
my $b = '1';
sub print_b
{
print $b;
}
$b = '2';
print_b();
您可以使用對原始變量的引用,並根據需要取消引用:
my $b = '1';
my $a = \$b;
$b = '2';
print $$a;
當代碼運行時,Perl會插值一個字符串,我不知道一種使其不這樣做的方法,缺少格式(這是丑陋的IMO)。 但是,您可以做的是將“代碼運行時”更改為更方便的方式,方法是將字符串包裝在子代碼中,並在需要插入字符串時調用它。
$b = "1";
my $a = sub { "\$b is $b" };
$b = "2";
print &$a;
或者,您可以進行一些評估,但這會更具侵入性(您需要對字符串進行一些處理才能實現)。
您想要的不是延遲評估,而是后期綁定 。 要在Perl中獲得它,您需要使用eval
。
my $number = 3;
my $val = "";
my $x = '$val="${number}"';
$number = 42;
eval $x;
print "val is now $val\n";
請注意, eval
通常效率低下,而且方法上的殘酷。 幾乎可以肯定,使用其他答案之一中的解決方案會更好。
正如其他人提到的那樣,Perl將僅在使用eval
在運行時調用編譯器編寫字符串時評估字符串。 您可以使用其他答案中指出的引用,但這會更改代碼的外觀( $$a
與$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
的文檔,但總而言之,它允許您定義自己的變量實現(用於標量,數組,哈希或文件句柄)。 因此,此代碼使用實現獲取或設置$b
的當前值(通過在內部存儲對$b
的引用)來創建新變量$a
。 並不是必須要使用這種new
方法(構造函數實際上是TIESCALAR
),但是它作為語法糖提供,以避免必須在調用代碼中直接使用tie
。
(將tie my $a, 'Lazy', $b;
)
您想假裝$ a指的是使用$ a時要評估的東西...您只能這樣做,如果$ a不是真正的標量,它可能是一個函數(如cHao的回答),或者用這種簡單的方式情況下,對另一個變量的引用
my $b="1";
my $a= \$b;
$b="2";
print $$a;
我希望$ {b}在需要$ a之前保持“不變”。
然后,我建議避開字符串插值,而不要使用sprintf
,以便在需要時“插值”。
當然,在此基礎上,您可以tie
一些快速(ish)和骯臟的東西tie
在一起:
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";
也可以與其他格式的說明符一起使用。 uck
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.