动态添加前导下划线到现有子

dynamically add leading underscore to existing sub

在这个 perl 书的例子中,“_components”来自哪里? 我知道添加 _ 以指示 sub 对包是私有的,但是这个似乎无处不在地使用领先分数。你能给我指出一些关于这个的消息来源吗?谢谢。

package Computer;
@ISA = qw(StoreItem);

sub new {
    my $pkg = shift;
    my $obj = $pkg->SUPER::new("Computer", 0,0);
    $obj->{_components} = [];
    $obj->components(@_);
    $obj;
}

sub components {
    my $obj = shift;
    @_ ? push (@{$ojb->{_components}}, @_) : @{$obj->{_components}};
}

sub price {
    my $obj = shift;
    my $price = 0;
    my $component;
    for my $component ($obj->components()) {
        $price += $component->price();
    }
    $price;
}

_components$obj 散列引用的文字键。它不是“来自”任何地方。这是 Perl 语法的一个怪癖。在声明中

$obj->{_components} = [];

$obj 是对 class 的新创建实例的引用(在前面的语句中),并且 _components 被定义为该实例中的键,并被初始化对空数组的引用。这相当于

$obj->{'_components'} = [];

例如

$ perl -de0

Loading DB routines from perl5db.pl version 1.55
Editor support available.

Enter h or 'h h' for help, or 'man perldebug' for more help.

main::(-e:1):   0
  DB<1> $obj->{a} = "hello";

  DB<2> x $obj
0  HASH(0x800756bf8)
   'a' => 'hello'
  DB<3> p $obj->{'a'}
hello
  DB<4> p $obj->{a}
hello
  DB<5>

_components 只是程序员选择的文字键名。之后,调用 components 可以访问刚刚创建的密钥。

部分问题是界面。 $obj->{_components} 处理非常低级别的细节,而 $self->components 是更高级别的细节。我不是特别喜欢混合抽象层次。

原始代码 components 根据参数列表的大小进行设置和获取。通过 autovivification,它会自动初始化 $obj->{_components},所以你不需要 $obj->{_components} = [] 行,除了设置第一个调用:

sub components {
    my $obj = shift;
    @_ ? push (@{$obj->{_components}}, @_) : @{$obj->{_components}};
}

但是,对于在设置任何组件之前不带参数调用的情况,我会在 components 中对其进行初始化:

sub components {
    my $obj = shift;
    $obj->{_components} = [] unless $obj->{_components};
    @_ ? push (@{$obj->{_components}}, @_) : @{$obj->{_components}};
}

使用 postfix deref 更简单:

use v5.26;
sub components {
    my $obj = shift;
    $obj->{_components} = [] unless $obj->{_components};
    @_ ? push ( $obj->{_components}->@* , @_) : $obj->{_components}->@*;
}

但我会改变它。 push return 是一个数字,这可能不是您想要的界面。摆脱条件运算符并始终 return 最后的完整列表:

use v5.26;
sub components {
    my $obj = shift;
    $obj->{_components} = [] unless $obj->{_components};
    push $obj->{_components}->@* , @_ if @_;
    $obj->{_components}->@*;
}

并且,回到您最初的查询:该键只是程序员选择的一个字符串。通常 _ 出现在键之前,以表明它是元数据或其他将被忽略的东西。我不知道这里的意图。不要多次输入,定义一次:

use v5.26;
sub components {
    state $key = '_components';
    my $obj = shift;
    $obj->{$key} = [] unless $obj->{$key};
    push $obj->{$key}->@* , @_ if @_;
    $obj->{$key}->@*;
}

使用 experimental signatures feature 可以稍微清理一下:

use v5.26;
use experimental qw(signatures);
sub components ($self, @args) {
    state $key = '_components';
    $obj->{$key} = [] unless $obj->{$key};
    push $obj->{$key}->@* , @args if @arg;
    $obj->{$key}->@*;
}