【问题标题】:How do I create an object list inside an object in perl?如何在 perl 中的对象内创建对象列表?
【发布时间】:2016-11-01 21:31:20
【问题描述】:

我是 Perl 的新手,抱歉我的愚蠢问题。

我搜索过,但没有找到方法。

我创建了一个类,它的一个属性需要是一个对象列表,我需要稍后调用这个列表。

我尝试将对象推送到列表中我收到消息:

匿名哈希中的奇数个元素...

我的包裹

package Squid;

use strict;
use warnings;

sub new
{
  my $class = shift;
  my $self = {@_ };

  print "Creating new $class\n";

  $self->{'filas'} = [];

  bless ($self, $class);

  return $self;
}

1;

这是脚本:

use Squid;
use warnings;
use strict;


my $fila = FilaSquid->new("nome" => 'Fila 1', "profundidade" => 45);
my $fila2 = FilaSquid->new("nome" => 'Fila 2', "profundidade" => 7);

my $squid = Squid->new("versao" => '1.0', "origem" => 'C:\temp', "filas" => @filas);

print "\nA versao da fila eh ".$squid->{versao};
print "\nA origem da fila eh ".$squid->{origem}."\n";

foreach my $line ($squid->{filas}) {
    print $line->{nome}."\n";
}

【问题讨论】:

  • 您运行的代码不是您显示的代码。 Global symbol "@filas" requires explicit package name (did you forget to declare "my @filas"?) at script.pl line 9. script.pl had compilation errors.。请参阅How to Ask 并提供minimal reproducible example
  • 这里有几个问题: (1) @filas 没有声明。您是否忘记声明并插入$fila$fila2? (2) FilaSquid 没有模块声明。 (3) 在您的构造函数中,您将覆盖$self->{'filas'},即使您也将它作为参数传递。 (4) 你可能不想将@filas 作为ARRAYREF 传递。

标签: list perl class object module


【解决方案1】:

第一个问题是new

$self->{'filas'} = [];

您正在将 $self->{'filas'} 初始化为一个空数组引用。这将吹走通过new 传入的任何内容。你可能想要的是:

$self->{filas} //= [];

等同于:

$self->{filas} = $self->{filas} // [];

// is the "defined-or" operator。这表示只有在未定义的情况下才初始化 $self->{filas}。这比使用||= 更安全一些,因为有些有效的东西是假的。


第二个问题是您如何将filas 传递给new。您正在使用数组 reference 初始化 $self->{filas} 是您的线索。

my @filas = (1, 2, 3, 4, 5, 6);

my $squid = Squid->new(
    "versao" => '1.0',
    "origem" => 'C:\temp',
    "filas" => @filas
);

这就像说:

my $squid = Squid->new(
    "versao" => '1.0',
    "origem" => 'C:\temp',
    "filas" => 1,
    2, 3, 4, 5, 6
);

你刚刚在应该是一个大小均匀的列表的末尾添加了一堆额外的东西,以用作哈希。

=> 运算符与逗号基本相同。它不会创建对,它只是允许您在其左侧的字符串周围省略引号。 key => @values 不是一对,而是key => $values[0], $values[1], $values[2], ...new 尝试将该列表视为哈希,只要元素数量为偶数,它就会“工作”。

相反,您需要传入一个数组referencekey => \@values.

my $squid = Squid->new(
    "versao" => '1.0',
    "origem" => 'C:\temp',
    "filas" => \@filas
);

【讨论】:

  • 可能需要[@filas],而不是\@filas
  • @ysth 可能是,如果他们想要一份副本。因为我们不知道它会被用来做什么...... *耸耸肩*。
  • ysth 的意思是\@filas 将导致传递给构造函数的数组的更改和对象的更改相互影响,这不太可能是所希望的。 [ @filas ] 创建一个新数组,它是作为参数传递的数组的副本,从而破坏了不幸的链接。 (我知道你知道这一点,Schwern。这是给其他读者的。)
  • @ikegami 我同意,但我反过来说。我没有让调用者决定对象将对引用做什么,而是让对象决定并在需要时复制它。也许它不会改变它,所以副本是浪费内存?也许它想操纵调用者的数据?不知道它对@filas 做了什么,所以... *耸耸肩*。无论如何,这都超出了问题的范围。他们很快就会到达那里。
【解决方案2】:

这是一种可以在不破坏封装的情况下将大量对象插入另一个对象的方法。它不关注现有代码中的任何问题,它只是回答问题。在此示例中,Two 包含多个 One 类的对象。每个内部对象都有一个名称:

use warnings;
use strict;

package One; {
    sub new {
        my ($class, %args) = @_;
        return bless {%args}, $class;
    }
    sub name {
        my $self = shift;
        return $self->{name};
    }
}

package Two; {
    sub new {
        return bless {}, shift;
    }
    sub add {
        my ($self, %args) = @_;
        my $name = $args{name};
        $self->{objects}{$name} = One->new(name => $name);
    }
    sub get_names {
        my ($self) = @_;
        return keys %{ $self->{objects} };
    }
    sub inner_obj {
        my ($self, $name) = @_;
        return $self->{objects}{$name};
    }
}

package main;

my $two = Two->new;

$two->add(name => 'obj1');
$two->add(name => 'obj2');

# loop over each inner object by name

for my $name ('obj1', 'obj2'){
    print $two->inner_obj($name)->name . "\n";
}

# or let Two give you the list of names back, and iterate
# automatically

for ($two->get_names){
    print $two->inner_obj($_)->name . "\n";
}

请注意,我们在主脚本中手动添加新对象。如果您需要在模块中而不是主模块中设置对象列表,这同样容易......您只需修改 Two::new() 以在内部调用其 add() 方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-17
    • 2011-03-12
    • 2014-07-22
    • 2021-03-02
    相关资源
    最近更新 更多