如何使用变量的值作为 Perl 变量名?

发布于 2024-08-11 20:29:10 字数 685 浏览 1 评论 0原文

对所有这些愚蠢的问题感到抱歉,我已经陷入 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 ${$尽管 x ${path} 打印 $path 中的值,但 key} 始终为 undef。

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

TIA

Sorry about all these silly questions, I've been thrust into Perl programming and I'm finding it really hard to think like a Perl programmer.

Silly question for today:
I load a pipe delimited file into a hash using the id field as the key, like so

#open file

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

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

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

There a few times, however, when I actually need the key to be the path because, for whatever reason (and no, it can't be changed) the id isn't unique, so I had the bright idea that I could put it all into a subroutine and pass the name of the variable to use as the key to it, kinda like so:

load_hash("path");

sub load_hash {
    my $key = shift;

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

but in perldb x ${$key} is always undef, although x ${path} prints the value in $path.

Is there some way of doing what I'm trying to?

TIA

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

明月夜 2024-08-18 20:29: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;
}

You're trying to use "symbolic references". If you have a problem and you think "hey, I'll solve this with symbolic references" you now have two problems.

First off, they only work on globals. You've declared $path as a lexical (only visible in the block which it was declared) and thus load_path can't see it. No, don't make $path global.

Second, symbolic refs create spaghetti code. Globals are bad enough. They can be accessed anywhere, anytime by anything. With a symbolic reference to a global you can't even see WHICH global is being accessed. This makes it impossible to track what might change what. This is why strict turns them off. Turn on strict and leave it on until you know when you should turn it off.

I'm not entirely sure what you're trying to accomplish, but it seems this is fine.

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

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

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

But I'd probably move the parsing of the line into a function and leave the hash assignment to the main loop. Parsing the line is a clear chunk of logic and can be totally separated from assigning the line to the file hash. A good sign is that %hash does not have to be global.

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;
}
私野 2024-08-18 20:29:10

像这样的东西吗?

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
    }
}

Something like this?

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
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文