Perl:循环变量使用相同的内存位置,导致覆盖问题

时间:2013-08-30 18:01:04

标签: perl

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的语法。

2 个答案:

答案 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;
}