FORWARD注:請爲討論的緣故,讓我們忽略了一會兒,同樣的結束可以有追索權的實現,以Class::Accessor,甚至根本事實使用Moose(可能在考慮代碼可讀性和可維護性時具有更好的結果)。使用閉包修改Perl中開始上課塊
關於面向對象的Perl,書Programming Perl
討論了使用閉包生成存取器方法的能力。例如,這是一個代碼有效片:
#!perl
use v5.12;
use warnings;
# at run-time
package Person1;
my @attributes = qw/name age address/;
for my $att (@attributes)
{
my $accessor = __PACKAGE__ . "::$att";
no strict 'refs'; # allow symbolic refs to typeglob
*$accessor = sub {
my $self = shift;
$self->{$att} = shift if @_;
return $self->{$att};
};
}
sub new { bless {}, shift }
package main;
use Data::Dumper;
my $dude = Person1->new;
$dude->name('Lebowski');
say Dumper($dude);
在上面的例子中,如果我沒有弄錯,類是由在運行時,在同一時間作爲類被創建及其訪問正在被實例化。這意味着在創建對象時會有速度懲罰。
現在考慮以下選擇:
#!perl
use v5.12;
use warnings;
package Person2;
BEGIN
{
for my $att (qw/name age address/)
{
my $accessor = __PACKAGE__ . "::$att";
no strict 'refs'; # allow symbolic refs to typeglob
*$accessor = sub {
my $self = shift;
$self->{$att} = shift if @_;
return $self->{$att};
};
}
}
sub new { bless {}, shift }
package main;
use Data::Dumper;
my $dude = Person2->new;
$dude->name('Lebowski');
say Dumper($dude);
在這個版本中,組成一個BEGIN
塊(即,在編譯時)內進行,而且我相信,只要完成這個任務處理可能在程序的生命週期中,我在運行時對象實例化過程中節省了時間。
一個簡單Benchmark
,
# benchmark it!
package main;
use Benchmark qw/cmpthese/;
cmpthese(-2, {
accessors_new => sub { Person1->new },
accessors_begin => sub { Person2->new },
});
看似支持我的理論與這些結果:
Rate accessors_begin accessors_new
accessors_begin 853234/s -- -9%
accessors_new 937924/s 10% --
假設我的推理一直是正確的,到目前爲止,
- 什麼其他的好處/在比較這兩種策略時存在缺陷嗎?
- 依靠
BEGIN
塊作爲進行這種類操作的有效方法是否是一個好主意? - 什麼時候不推薦?
所以,其實我沒有節省時間。只需將相同的工作量(一次執行)轉移到程序中的不同點。謝謝。 – 2012-03-07 14:26:15
@SérgioBernardino確切的。 Class :: Accessor使用非常類似的技術,用閉包構建訪問器,只是具有更大的靈活性。 Class :: Accessor :: Fast幾乎就是你寫的。麋可能會這樣做,或者它可能會評估一個字符串,我不確定。 – Schwern 2012-03-07 22:01:23