sub read_file {
open("person_file", "<person_data.txt");
my $class = shift;
my @people;
while (<person_file>) {
# entries are delimited by a | character
# format is
# firstname|lastname|streetaddress|town|state|zipcode
my $line = $_;
chomp($line);
my @broken_line = split(/\|/, $line);
print Dumper(@broken_line);
my $curr_person = new Person;
$curr_person->set_first_name($broken_line[0]);
$curr_person->set_last_name($broken_line[1]);
$curr_person->set_street_address($broken_line[2]);
$curr_person->set_town($broken_line[3]);
$curr_person->set_state($broken_line[4]);
$curr_person->set_zip_code($broken_line[5]);
print $curr_person->get_full_name(), "\n",
$curr_person->get_full_address(), "\n";
push(@people, $curr_person);
}
print "\n\n\n";
foreach my $person (@people) {
print $person->get_full_name(), "\n", $person->get_full_address(), "\n";
}
print Dumper(@people);
print "\n\n\n";
close("person_file");
return \@people;
}
这是输出:
$VAR1 = 'K';
$VAR2 = 'M';
$VAR3 = '4th St';
$VAR4 = 'New York';
$VAR5 = 'NY';
$VAR6 = '10001';
K M
4th St
New York, NY 10001
$VAR1 = 'C';
$VAR2 = 'G';
$VAR3 = '3 Fifth Ave';
$VAR4 = 'New York';
$VAR5 = 'NY';
$VAR6 = '10003';
C G
3 Fifth Ave
New York, NY 10003
C G
3 Fifth Ave
New York, NY 10003
C G
3 Fifth Ave
New York, NY 10003
$VAR1 = bless( do{\(my $o = 'Person')}, 'Person' );
$VAR2 = bless( do{\(my $o = 'Person')}, 'Person' );
当我读取文件时,第一个输出块出现在循环中。第二个是在第二个循环中,我检查数组只是为了查看所有变量是否正确,它们不是。 所以我想到的问题是$ curr_person即使超出范围或被称为新人,也不会收到新的内存位置;并将与$ people [0]等共享内存位置,以便人们中的所有元素都被$ curr_person中的所有元素覆盖。
有没有办法让$ curr_person在循环的每次迭代中获得一个新的内存位置?
由于
人员类:
package Person;
use strict;
use warnings;
my $first_name;
my $last_name;
my $street_address;
my $town;
my $state;
my $zip_code;
my $unique_id;
sub new
{
my $instance = shift;
bless \$instance, "Person";
}
这是我的第一个非练习(5行)Perl项目,我仍然试图理解Perl中OOP的语法。
答案 0 :(得分:1)
您需要的答案已经在注释中:Person构造函数必须每次都返回相同的实例,因此@people
数组中的每个项都是指向同一实例的指针,当您更新一个时你正在更新所有。
向我们展示Person::new
的代码。
<强>后来强>:
感谢您的代码。结果我猜错了:并不是你的构造函数每次都返回相同的实例。问题在于您的数据存储:每个不同的Person实例使用相同的变量集(my
下的package Person;
声明),正如您已经体验过的那样,当您更新一个{{1}时你已经全部更新了它们。
使用带有get和set方法的类的示例,查找教程或教科书,并特别注意每个实例如何设置将其数据(名字,姓氏等)与所有数据分开其他人。
答案 1 :(得分:1)
方法将invocant作为第一个参数。调用对象时,调用者是对象:
$person->foo(); # $_[0] is Person object
在该类上调用或类名(作为纯字符串):
Person->foo(); # $_[0] is "Person" string
通常的new
方法如下所示:
# Usage: Person->new(first_name => "Fred", last_name => "Flintstone")
sub new {
my ($class, %args) = @_;
# process arguments
bless \%args => $class;
}
第一个参数是类名。我们祝福那个班级(不一定是Person
!),这样我们的班级就可以继承,而new
方法可以重复使用。
在其他方法中,我们使用对象中的字段(这只是一个特殊的hashref)来存储数据 - 但不是全局或词汇变量!
sub first_name {
my $self = shift;
if (@_) { # if there are args
$self->{first_name} = shift;
}
return $self->{first_name};
}
等等。 perlootut中对此进行了解释,您
因为编写new
和访问器是重复和无聊的,所以人们已经提出了智能对象框架,使得处理对象更具表现力。最重要的是Moose
framework。然后我们可以写:
package Person;
use Moose; # this is now a Moose class
# declare attributes with `has`:
has first_name => (
is => 'rw', # this is now a read-write attribute
)
...
has street_address => ( is => 'rw');
has town => ( is => 'rw');
has state => ( is => 'rw');
has zip_code => ( is => 'rw');
...
# new is autogenerated!
# a normal method
sub get_full_address {
my ($self) = @_;
return sprintf "%s\n%s, %s %s",
$self->street_address, $self->town, $self->state, $self->zip_code;
}