PERL - 参数/返回/重用中的哈希值

时间:2017-10-30 13:36:39

标签: perl hash reference return arguments

我希望通过多次应用函数来连续填充哈希表。该函数在参数中使用哈希引用,填充它并返回它。该函数在参数中再次获取哈希值。 似乎哈希根本没有填充。

这是我的代码:

有人能告诉我哪里可能有错误吗?

sub extractMLResult {
    my (%h1, %h2, %h3, %h4, $param) = @_;
    my $h1= shift;
    my $h2= shift;
    my $h3= shift;
    my $h4=shift;
    $params= shift;

    # read csv file, split it, fill hashes with values 
    $h1->{$key1}{$key2}{'p'}=$val1;
    # ... do the same for the other hashes ... 
    return (%$h1, %$h2, %$h3, %$h4);
}

my %myhash = ();
my %h1= ();
my %h2= ();
my %h3= ();
my %h4= ();
$myhash{'a'}{'x'}=1;
$myhash{'b'}{'y'}=1;


if (exists $myhash{'a'}){
    (%h1, %h2, %h3, %h4) = extractMLResult(\%h1, \%h2, \%h3, \%h4, 'a');
}

if (exists $myhash{'b'}){
    (%h1, %h2, %h3, %h4) = extractMLResult(\%h1, \%h2, \%h3, \%h4, 'b');
}

2 个答案:

答案 0 :(得分:2)

my在词法范围内声明变量。因此,当您退出“if”子句时,%$h1等会再次消失。

另外,你在做分配方面做了一些奇怪的事情,我认为这不会像你想象的那样工作 - 你正在引用你的哈希引用,并因此返回一个值列表。

由于列表分配的工作方式,所有将进入%$h1

但另一方面 - 当你在myfunction阅读时,你的作业可能没有按照你的想法行事。

因为您正在调用myfunction并传递值列表,但您正在为%h1执行列表分配。这意味着你所有的论据都被“消耗”了:

#!/usr/bin/env perl

use strict;
use warnings;

use Data::Dumper;
sub myfunction {
    my (%h1, %h2, %h3, %h4, $param) = @_;
    print Dumper \%h1; 

    print Dumper \%h2; 
}

# launch function : 

my %h1 = ( a => "test" );
my %h2 = ( b => "wibble" );

myfunction ( \%h1, \%h2 );

正如您将看到的那样 - 您的参数全部由%h1的作业消耗,其余任务都没有。

更重要的是 - 您的代码甚至无法编译,因为如果您这样做:

 my (%$h1, %$h2, %$h3, %$h4) = myfunction (\%h1, \%h2, \%h3, \%h4, "a");

你得到:

Can't declare hash dereference in "my"

所以也许给我们一些实际说明问题的示例代码 - 并运行一些示例数据?

编辑:使用更多代码 - 问题就在这里:

sub extractMLResult {
    my (%h1, %h2, %h3, %h4, $param) = @_;

因为那不符合你的想法。因为%h1是一个哈希值,并且它是在列表上下文中分配的 - 所有@_的参数都插入其中。因此%h2, %h3, %h4, $param将始终为空/未定义。

你并没有表明你是否实际使用%h1,这只是意味着它是混乱的废话 - 可能。

但是这一点:

    my $h1= shift;
    my $h2= shift;
    my $h3= shift;
    my $h4_parents = shift;

好的,所以你在这里提取一些哈希引用,这可能更加理智。但是命名与哈希相同是令人困惑的 - $h1%h1之间存在 NO 关系,如果你这样做,你会在代码中混淆。 (因为$h1{key}来自%h1而与$h1无关。)

但回归中存在同样的问题:

(%h1, %h2, %h3, %h4) = extractMLResult(\%h1, \%h2, \%h3, \%h4, 'a');

因为您的return

return (%$h1, %$h2, %$h3, %$h4);

此返回将返回包含散列中所有元素的展开列表。但考虑到你打包哈希的方式,它们可能是部分展开的列表,包含哈希引用。

但是,在作业中,他们将所有再次由%h1消费。

你需要:

返回($ h1,$ h2,$ h3,$ h4);

然后在你的函数中:

($ h1_ret,$ h2_ret,$ h3_ret,$ h4_ret)= extractMLResult(\%h1,\%h2,\%h3,\%h4,'a');

然后解压缩:

%h1 = %$h1_ret; 

或者只是坚持使用参考文献,这对所有相关人员来说可能更清楚。

答案 1 :(得分:1)

You are passing hash references into your subroutine. This is a good idea. But inside your subroutine, you are treating your parameters as hashes (not hash references). This is a bad idea.

A hash is initialised from a list. It should be a list with an even number of elements. Each pair of elements in the list will become a key/value pair in the hash.

my %french => ('one', 'un', 'two', 'deux', 'three', 'trois');

We often use the "fat comma" to emphasise the link between keys and values.

my %french => (one => 'un', two => 'deux', three => 'trois');

This means that hash initialisation is a greedy operation. It will use up all of any list that it is given. You cannot initialise two hashes in the same statement:

my (%french, %german) = (one => 'un', two => 'deux',
                         three => 'drei', four => 'vier');

This doesn't work, as all of the pairs will end up in %french, leaving nothing to populate %german.

This is the same mistake that you are making when extracting the parameters within your subroutine. You have this:

my (%h1, %h2, %h3, %h4, $param) = @_;

Nothing will end up in %h2,%h3,%h4or$paramas the assignment to%his greedy and will take all of the data values from@_` - leaving nothing for the other variables.

But, as you are passing hash references, your code shouldn't look like that. A hash reference is a scalar value (that's pretty much the point of them) so it is stored in a scalar variable.

What you want is this:

# Note, scalars ($), not hashes (%)
my ($h1, $h2, $h3, $h4, $param) = @_;

This should get you started. Note also, that you'll now need to deal with hash references ($h1->{key}) rather than hashes ($h1{key}).

And, please, always include both use strict and use warnings.