如何解析传递给定义为在Perl中接受2个参数的子例程的一个参数

时间:2017-09-14 18:26:11

标签: perl subroutine

我正在创建一个新对象,如下所示:

my $new_obj = new P_module({key => 'abc'});

P_module的构造函数定义如下:

sub new {
    my ($pkg, $input) = @_;
    my $obj = {};
    bless ($obj, ref($pkg)||$pkg);
    $obj->{key} = $input->{key};
 }

根据我的阅读,由于哈希作为参数传递给new,因此它将表示为2元素数组。因此,pkg应为keyinput应为abc。然后,obj如何持有关键key以及$input->{key}甚至意味着什么?

4 个答案:

答案 0 :(得分:6)

首先,

my $new_obj = new P_module({ key => 'abc' });

最好写成

my $new_obj = P_module->new({ key => 'abc' });

这是

的缩写
my %anon = ( key => 'abc' );
my $new_obj = P_module->new(\%anon);

进行方法调用时,调用者(->左边的内容)作为第一个参数传递。这意味着$pkg是字符串P_module$input{ key => 'abc' }返回的引用。

由于$input是对散列的引用,$input->{key}从引用的散列中获取具有键key的元素的值。

我怎么会写这个:

sub new {
    my ($class, %args) = @_;
    my $self = bless({}, $class);      # If base class.
    #my $self = $class->SUPER::new();  # If inheriting.
    $self->{key} = $args{$key};
    return $self;
 }

 my $obj = P_module->new( key => 'abc' );

呼叫者不需要哈希,并且没有理由支持$existing_obj->new。它还使用更多标准名称$class$self

答案 1 :(得分:2)

你有理由拥有这个:

bless ($obj, ref($pkg)||$pkg);

而不是这个?

bless ($obj, $pkg);

如果没有,那么我假设你切断&从某个地方的其他代码粘贴它。你可能想要的是后者。

ref($pkg)||$pkg允许您这样做:

my $new_object = $existing_obj->new;

而不是

my $new_object = new Classname;

由于您可能不需要这样做,所以只需坚持使用

bless ($obj, $pkg);

答案 2 :(得分:0)

周围的花括号创建一个哈希引用或hashref,它是一个单标量。参数值为

  • $pkg - 包含的包的名称,可能是"P_module"
  • $input - 对提供的哈希的引用

代码$input->{key}访问与密钥"key"关联的值,该密钥由调用者提供

my $new_obj = new P_module({key => 'abc'});

将其写为

被认为是更好的风格
my $new_obj = P_module->new({key => 'abc'});

您可以添加另一个键,如

my $new_obj = P_module->new({key => 'abc', other => 'unused'});

"key"关联的值将通过

复制到对象的状态
$obj->{key} = $input->{key};

请注意,Perl子例程返回最后一个表达式的值,因此您的代码存在错误。您希望P_module::new的最后一行是

bless ($obj, ref($pkg)||$pkg);

因为那将返回可以用来调用其他方法的祝福对象,例如

my $new_obj = new P_module({key => 'abc'});
print $new_obj->other_method_that_you_must_define(), "\n";

答案 3 :(得分:0)

调用方法时,对象本身会在幕后传递;或者,如果子使用bless,则它是构造函数,而是传递类名。因此任何方法都接收对象或类名作为其第一个参数。其余的是明确传递给方法的参数。

你传递哈希引用 {...},什么是标量。所以这被分配给$input,因为"非常"传递的类名称已分配给$pkg

该接口的构造函数带有哈希引用,通常最简单地写为

sub new {
    my ($class, $input) = @_;
    my $self = { %$input };
    return bless $self, $class;
}

其中return可以省略,因为返回了最后一个计算语句的返回值。最后两行可以写成return bless { %$input }, $class;,并且(匿名)hashref被初始化,祝福它的包$class(所以它是一个对象),然后返回。

请注意,您不必传递hashref;简单的哈希使得界面更清晰。如果可能还有其他参数,则需要使用引用, 使解析所有这些成为可能。

但是,您通常希望处理参数。例如,必须检查它们是否符合您的类支持的内容,而不是盲目地将用户传递的键分配给属性。如果你提供默认值,则计算出默认值,如果需要则检查值等等。

这种数据初始化有时会分成单独的子程序。例如

sub new {
    my ($class, $input) = @_;
    my $self = {};
    bless $self, $class;       # $self is an object now
    $self->_init($input);      # on which methods can be called
    return $self;
}

sub _init {
    my ($self, $args) = @_;
    # Check arguments, work out defaults (etc), 
    # then assign to self as appropriate
    %$self = %$args;
}

代码写入"返回"通过引用,以便更新$self中的new

这应该与普通方法调用一起使用

my $new_obj = P_module->new({key => 'abc', other => '...'});
使用间接表示法 new P_module

。构造函数,通常称为new(只是通过自定义 - 你可以调用它你想要的),是一个普通的sub特殊,因为它bless是一个引用(通常是一个哈希引用),因此通过类名而不是对象。因此,它知道"它的包装是一个对象。

文献:perlmod(一个类是一个包),教程perlootut和参考perlobj

一旦您熟悉了Perl内置的面向对象设施,我建议您这样做,有许多模块可以让所有这些(以及更多)更容易实现。

首先推荐的是非常现代的Moose及其轻量级Moo