我有一个包含以下子程序的模块:
package module;
sub new
{
my $class = shift;
my $reference = shift;
bless $reference, $class;
return $reference;
};
sub add_row{
@newrow = [1,1,1];
push @_, @newrow;
};
@matricies是数组引用的数组。我使用
从数组引用中创建了对象my @object= map{module->new($_)} @matrices;
并且假设我想使用以下命令向其中一个对象添加行:
@object[0]->add_row();
我认为add_row子程序处理@和$的使用有问题。有什么想法吗?
答案 0 :(得分:4)
是的,您正在添加数组引用,但您的变量是一个数组。
你需要做的第一件事(在使用严格和警告之后)是阅读以下关于Perl中的符号的文档(除了好的Perl书):
https://stackoverflow.com/a/2732643/119280 - brian d。 foy的精彩总结
此SO answer
我可以为您提供有关在Perl中访问数据结构的语法的最佳摘要(引自我之前的评论)
sygil表示您要检索的数据结构中的数据量(1个元素的$,元素列表的@,整个哈希的%)
而大括号样式代表你的数据结构(数组的正方形,散列的卷曲)。
现在,为您的代码:
@newrow = [1,1,1];
push @_, @newrow;
应该是
my $newrow = [1,1,1];
push @_, $newrow;
如何从对象访问行还有另一个问题:
sub add_row {
my ($self, $newrow) = @_;
$newrow ||= [1,1,1]; # In case it wasn't passed, default to this?
push @{$self}, $newrow;
};
你对@object[0]->add_row();
和newrow也有同样的问题 - 你使用数组sigil来解决1个元素
$object[0]->add_row(); # will add default row of [1,1,1]
$object[0]->add_row([2,3,4]);
更新:这是一个完整的代码:
模块的add_row()(你的构造函数很好):
sub add_row {
my ($self, $newrow) = @_;
$newrow ||= [1,1,1]; # In case it wasn't passed, defauly to this?
push @{$self}, $newrow;
};
测试驱动程序:
use a1;
my @objects = (a1->new([[5,6,7],[8,9,10]]));
$objects[0]->add_row();
$objects[0]->add_row([3,4,5]);
use Data::Dumper; print Data::Dumper->Dump([\@objects]);
结果:
$VAR1 = [
bless( [
[
5,
6,
7
],
[
8,
9,
10
],
[
1,
1,
1
],
[
3,
4,
5
]
], 'a1' )
];
答案 1 :(得分:2)
好的,备份。
首先,您需要use strict;
和use warnings;
。总是。每一次都是。如果你不这样做,那你就是在乞求麻烦。
此外,@newrow = [1,1,1];
不正确,因为@newrow
表示数组,但[1,1,1]
是数组引用。此外,@newrow
仅在您的子例程中定义,因此add_row
实际上没有做任何事情。您需要的是将引用传递给要添加行的矩阵。
我认为你要做的是将矩阵建模为数组引用数组。所以,例如,如果我们有
my @matrix=([1,0,0],[0,1,0],[0,0,1]);
然后可以将其视为包含[1,0,0]
,[0,1,0]
和[0,0,1]
行的矩阵。
因此,忽略了创建模块的想法,您可能正在寻找的内容如下:
use strict; #ALWAYS
use warnings; #ALWAYS
#array of three array references, each of which has three elements.
my @matrix=([1,0,0],[0,1,0],[0,0,1]);
#The arguments to add_row are (in order):
#1. A reference to the matrix to which you want to add a row.
#2. A list of the elements that you wish to add.
sub add_row
{
my $matrix_arg=shift;
my @new_row_array=@_;
#Now, we do the necessary push:
push @$matrix_arg,\@new_row_array;
}
#Now we can add a row and check whether or not we we are successful:
add_row(\@matrix,2,-17,5);
foreach my $row (@matrix)
{
print join(",",@$row) . "\n";
}
输出结果为:
1,0,0
0,1,0
0,0,1
2,-17,5
老实说,我建议您亲自阅读Learning Perl的副本并查看perldoc perlref
。
答案 2 :(得分:1)
只是一些事情:
Local::Module
代替module
。 Local
模块空间保留给非CPAN模块。此外,按照惯例,模块名称应以大写字母开头。use strict
和use warnings
。让我们看一下你的new
子程序构造函数:
sub new
{
my $class = shift;
my $reference = shift;
bless $reference, $class;
return $reference;
};
我不确定你在这里尝试做什么。通常,这应该是一个构造函数。你得到一个引用对象,你不会传给它一个引用。也许你的意思是这个?
package Local::Module;
sub new {
my $class = shift;
my $reference = {};
bless $reference, $class;
return $reference;
}
这将创建一个可用于添加的新对象。所以,你先做到这一点:
my $object = Local::Module->new;
现在,您可以使用$object
作为行的句柄:
sub add_rows {
my $self = shift;
my $rowRef = shift;
if (not exists $self->{ROWS}) {
$self->{ROWS} = [];
}
push @{$self->{ROWS}}, $rowRef;
}
现在,您可以使用此对象添加行:
my $object->add_row = $RowReference;
请注意,Perl中的对象通常是对匿名哈希的引用。您将所需的数据放在哈希的其中一个键中。在这种情况下,您将数组放入$ self-> {ROWS}。
是的,有各种各样的方法可以创建伪哈希,内部哈希,但想法是你的类通常不是实际数据,而是对保存数据的对象的引用。否则,你并没有真正使用面向对象的编程。
在你的情况下,我不会打扰map
。我怀疑它会更有效率,并且for循环将更清洁(未经测试):
use strict;
use warnings;
my @matrices = ([1,0,0],[0,1,0],[0,0,1]);
my @objects;
foreach my $array_ref (@matrices) {
my $module_ref = Local::Module->new;
my $module_ref->add_row($array_ref);
push @objects, $module_ref;
}
package Local::Module;
sub new {
my $class = shift;
my $reference = {};
bless $reference, $class;
return $reference;
}
sub add_rows {
my $self = shift;
my $rowRef = shift;
if (not ref($rowRef) eq "ARRAY") {
die qq(Method "add_rows" can only take an Array reference);
}
if (not exists $self->{ROWS}) {
$self->{ROWS} = [];
}
push @{$self->{ROWS}}, $rowRef;
}
现在,您的@objects
列表是Local::Module
类的列表。你现在可以这样做:
$objects[2]->add_row($row_ref);
这是一个非常粗略的轮廓。例如,您可能希望另一个模块返回对所有数组的引用。也许另一个可以弹出并移动数组中的行,并返回弹出或移位的行。
您可能还想要包含一种传递对数组的初始引用的方法:
sub new {
my $class = shift;
my $array_ref = shift;
my $reference = {};
bless $reference, $class;
if (defined $array_ref) {
$reference->add_row($array_ref);
}
return $reference;
}
请注意,一旦我祝福$reference
,我就可以在面向对象的调用中使用它。这样,我的构造函数不知道我的对象是什么样的。一般认为构造函数和方法应该不知道对象的其余部分是如何构造的。这样,当您修改对象时,您只需要修改一个或两个隔离的方法。如果我改变方法add_rows
的工作方式,我不必修改我的构造函数。更改将在一个位置隔离。
答案 3 :(得分:0)
@_是一个临时变量,仅用于将参数传递给函数,因此将参数放在其上不会修改对象本身。
相反,您需要从@_数组中取出对象,然后再修改它。
sub add_row{
my $self = shift;
@newrow = (1,1,1);
push @$self, @newrow;
};