1

对于所有这些愚蠢的问题,我很抱歉,我已经被投入到 Perl 编程中,我发现很难像 Perl 程序员一样思考。

今天的愚蠢问题:我使用 id 字段作为键将管道分隔文件加载到哈希中,就像这样

#open file

my %hash;
while (<MY_FILE>) {
    chomp;

    my ($id, $path, $date) = split /\|/;

    $hash{$id} = {
        "path" => $path,
        "date" => $date
    };
}

然而,有几次,当我实际上需要密钥作为路径时,因为无论出于何种原因(不,它不能更改),id 不是唯一的,所以我有一个好主意,我可以提出将其全部放入一个子例程并传递变量的名称以用作它的键,有点像这样:

load_hash("path");

sub load_hash {
    my $key = shift;

    #do stuff, and then in while loop
    $hash{${$key}} = #and so on
}

但是在 perldb 中 x ${$key} 总是 undef,尽管 x ${path} 打印 $path 中的值。

有什么方法可以做我想做的事吗?

TIA

4

2 回答 2

10

您正在尝试使用“符号引用”。如果你有一个问题并且你认为“嘿,我会用符号引用解决这个问题”你现在有两个问题。

首先,它们仅适用于全局变量。您已声明$path为词法(仅在声明它的块中可见),因此 load_path 看不到它。不,不要$path全球化。

其次,符号引用创建意大利面条代码。全球人已经够糟糕了。它们可以随时随地通过任何方式访问。通过对全局的符号引用,您甚至看不到正在访问哪个全局。这使得无法跟踪可能会改变什么。这就是strict关闭它们的原因。打开strict并保持打开状态,直到您知道何时应该将其关闭。

我不完全确定您要完成什么,但这似乎很好。

my %hash;
while (<MY_FILE>) {
    chomp;

    my ($id, $path, $date) = split /\|/;

    $hash{$path} = {
        "path" => $path,
        "date" => $date
    };
}

但是我可能会将行的解析移到一个函数中,并将散列分配留给主循环。解析行是一个清晰的逻辑块,可以与将行分配给文件哈希完全分开。一个好的迹象是,%hash它不必是全球性的。

my %hash;
while (<MY_FILE>) {
    my $line = parse_line($_);

    my $id = $line->{path};
    $hash{$id} = $line;
}


my @fields = qw(id path date);
sub parse_line {
    my $line = shift;
    chomp $line;

    my %data;
    # This is assigning to a hash slice.  Look it up, its handy.
    @data{@fields} = split m{\|}, $line;

    return \%data;
}
于 2009-11-13T00:51:58.780 回答
2

像这样的东西?

use Carp 'confess';

sub load_hash {
    my $key = shift;

    # ...

    while (...) {
        # ...
        my %line;  # important that this is *inside* the loop
        @line{qw (id path date)} = split /\|/;
        confess "BUG: unknown key '$key'"  unless exists $line{$key};  # error checking
        $hash{$line{$key}} = \%line;
        delete $line{$key};  # assuming you don't want the key value duplicated
    }
}
于 2009-11-13T00:30:01.000 回答