为什么这会复制或覆盖列表的内容?

时间:2014-09-04 16:40:40

标签: arrays perl list hash push

我是Perl的新手,我的代码可能无法解决问题。我相信我正确地使用了语法,但我怀疑问题可能在于这一行:

push @students, \%information;

我想要的是学生列表中包含学生信息的哈希值。我期望的是,在每次添加学生之后,创建学生信息的另一个哈希并且链接到列表的最新索引。但是,如果我同时输入学生数据,则最新会覆盖之前的数据,因此当您打印它时,您将在上一个列表条目中看到最新输入信息的副本。如果我输入1名学生并在添加后立即查看,则输入另一名学生,最新学生将覆盖以前的学生。有人可以解释一下吗?谢谢!

这是我的代码:

use strict;
use warnings;

my $userchoice = 0;
my $i;
my @students    = ();    #empty array
my %information = ();

while ( $userchoice != 4 ) {
    print "------------------------------\n";
    print "Welcome! What would you like to do?\n";
    print "[0]Create Student Record\n";
    print "[1]Edit Student Record\n";
    print "[2]View Student Record\n";
    print "[3]Delete Student Record\n";
    print "[4]Exit\n";
    print "Your Choice : ";
    $userchoice = <STDIN>;
    chomp($userchoice);

    if ( $userchoice == 0 ) {
        print "-----------\n";
        print "CREATE STUDENT RECORD.\n";
        if ( $#students <= 9 ) {
            print "Name : ";
            $information{"name"} = <STDIN>;
            chomp( $information{"name"} );
            push @students, \%information;
        }
        print "Student Record Full. " if ( $#students >= 10 );
    }

    if ( $userchoice == 2 ) {
        print "\nVIEW STUDENTS.\n";
        print "[0]View One Student\n";
        print "[1]View All Students\n";
        print "[2]Back to Main Menu\n";
        print "Your Choice : ";
        $userchoice = <STDIN>;
        if ( $userchoice == 1 ) {
            print "VIEW ALL STUDENTS.\n";

            print "STUDENT 1---------------\n";
            print "Name : ", $students[0]->{"name"}, " \n";
            print "STUDENT 2---------------\n";
            print "Name : ", $students[1]->{"name"}, " \n";
        }
    }
}

3 个答案:

答案 0 :(得分:4)

这总是将对同一哈希的引用推送到数组push @students,\%information; 举例说明:

my %hash = ( index => 0 );
my @list = ();
foreach my $i (1..3) {
    $hash{index} = $i;
    push @list, \%hash;
}

for ( my $i=0; $i<@list; $i++ ) {
    print "item $i - $list[$i] - $list[$i]->{index}\n";
}

从输出中注意每个地址的地址相同:

item 0 - HASH(0x4c8068) - 3
item 1 - HASH(0x4c8068) - 3
item 2 - HASH(0x4c8068) - 3

您可以通过在循环中声明%信息来修复

while($userchoice!=4){
    my %information = ();

或者在推送时强制使用新参考:

push @students, { %information };

答案 1 :(得分:2)

您的问题出现是因为您为每个学生提供了数组中相同哈希的引用:

push @students, \%information;

对此的一个解决方案是简单地为每条记录创建一个新的匿名哈希:

push @students, { %information };

但是,我相信您也可以使用课程来限制变量的范围。

在声明变量时始终使用尽可能小的范围。这既有助于记录您的代码,也可以减少意外滥用此类变量的可能性。

以下是重写脚本以删除全局范围中使用的所有变量:

use strict;
use warnings;

my @students = ();    #empty array

while (1) {
    print "------------------------------\n";
    print "Welcome! What would you like to do?\n";
    print "[0]Create Student Record\n";
    print "[1]Edit Student Record\n";
    print "[2]View Student Record\n";
    print "[3]Delete Student Record\n";
    print "[4]Exit\n";
    print "Your Choice : ";
    chomp( my $userchoice = <STDIN> );

    last if $userchoice == 4;

    if ( $userchoice == 0 ) {
        print "-----------\n";
        print "CREATE STUDENT RECORD.\n";
        if ( @students <= 10 ) {
            print "Name : ";
            chomp( my $name = <STDIN> );
            push @students, { name => $name };
        }
        print "Student Record Full. " if ( @students > 10 );
    }

    if ( $userchoice == 2 ) {
        print "\nVIEW STUDENTS.\n";
        print "[0]View One Student\n";
        print "[1]View All Students\n";
        print "[2]Back to Main Menu\n";
        print "Your Choice : ";
        chomp( my $userchoice = <STDIN> );
        if ( $userchoice == 1 ) {
            print "VIEW ALL STUDENTS.\n";

            for my $i ( 1 .. @students ) {
                print "STUDENT $i---------------\n";
                print "Name : ", $students[ $i - 1 ]{"name"}, " \n";
            }
        }
    }
}

答案 2 :(得分:1)

如评论中所述:

  

每次都需要使用对新哈希的引用,而不是每次都尝试引用相同的哈希。最简单的方法是在循环体内定义%information

您的代码目前是:

my %information = ();

while ( $userchoice != 4 ) {
    print "------------------------------\n";

如果使用:

,它将正常工作(或者至少,它的这方面可以正常工作)
while ( $userchoice != 4 ) {
    my %information = ();
    print "------------------------------\n";