将多个值分配给哈希引用 - 数组

时间:2012-05-23 18:07:28

标签: perl

我声明了以下子(实际上,值来自数据库 - 所以我简化了它):

sub get_date {
 my ($ref_last)=@_;
 $$ref_last->{duration}='24,0,4';
 ($$ref_last->{duration}->{d},
  $$ref_last->{duration}->{h},
  $$ref_last->{duration}->{m})
   = split(/\,/, $$ref_last->{duration});
}

从脚本的主要部分调用此子句,如下所示:

my $hashy;
get_date(\$hashy);
print $hashy->{duration}->{d};

一切都很好,并且像魅力一样,直到我使用严格:

use strict;
my $hashy;
get_date(\$hashy);
print $hashy->{duration}->{d};

在这种情况下,perl说“不能使用字符串(”24,0,4“)作为HASH参考,而”严格参考“正在使用

我已经尝试过ref($ref_last) - 但ref是一个只读函数。

任何建议,为什么会发生这种情况 - 也许是更好的解决方案?

这是完整的(非)工作脚本:

#!/usr/bin/perl -w
use strict;
my $hashy;
get_date(\$hashy);
print $hashy->{duration}->{d};

sub get_date {
        my ($ref_last)=@_;
        $$ref_last->{duration}='24,0,4';
        ($$ref_last->{duration}->{d},
         $$ref_last->{duration}->{h},
         $$ref_last->{duration}->{m})
                = split(/\,/, $$ref_last->{duration});
}

3 个答案:

答案 0 :(得分:2)

根据评论,您尝试更改现有哈希值的格式(从“24,0,4”到“{ d=>24, h=>0, m=>4 }”)。我就是这样做的。

sub split_duration {  # Changes in-place.
    my ($duration) = @_;
    my %split;
    @split{qw( d h m )} = split(/,/, $duration);
    $_[0] = \%split;
}

my $row = $sth->fetchrow_hashref();
split_duration( $row->{duration} );

sub split_duration {
    my ($duration) = @_;
    my %split;
    @split{qw( d h m )} = split(/,/, $duration);
    return \%split;
}

my $row = $sth->fetchrow_hashref();
$row->{duration} = split_duration( $row->{duration} );

下面的问题解释和初步解决方案。


如果没有严格,24,0,4被视为哈希引用,这意味着Perl正在创建一个名为$24,0,4的变量!这很糟糕,这就是use strict 'refs';阻止它的原因。

潜在的问题是您尝试将两个值分配给$$ref_last->{duration}:字符串

'24,0,4'

和对哈希的引用

 { d => 24, h => 0, m => 4 }

它不能兼得。您需要重新排列数据。

我怀疑你在拆分后实际上没有使用24,0,4,所以你可以修改代码如下:

sub get_date {
    my ($ref_last)=@_;
    my $duration = '24,0,4';
    @{ $$ref_last->{duration} }{qw( d h m )} =
        split(/,/, $duration);
}

如果您需要24,0,4,则可以重新构建它。或者,您可以将合并的持续时间与d,h,m一起存储。

sub get_date {
    my ($ref_last)=@_;
    my $duration = '24,0,4';
    $$ref_last->{duration}{full} = $duration;
    @{ $$ref_last->{duration} }{qw( d h m )} =
        split(/,/, $duration);
}

或者在较高的哈希值的单独元素中。

sub get_date {
    my ($ref_last)=@_;
    my $duration = '24,0,4';
    $$ref_last->{full_duration} = $duration;
    @{ $$ref_last->{duration} }{qw( d h m )} =
        split(/,/, $duration);
}

答案 1 :(得分:2)

get_date内,您将字符串分配给$ref_last->{duration},但随后尝试像hashref一样访问它。您还有额外的美元符号,试图取消引用从哈希中提取的单个值。

我会把它写成

sub get_date {
  my($ref_last) = @_;
  my $duration = '24,0,4';
  @{ $ref_last->{duration} }{qw/ d h m /} = split /\,/, $duration;
}

最后一行是hash slice,可让您在单个列表分配中为dhm键指定值。

在调用者的上下文中,您需要设置一些脚手架。

my $hashy = {};
get_date($hashy);

如果不初始化$hashy以包含新的空hashref,get_date会完成所有分配,然后抛弃新建的大厦。这是因为当您从@_复制参数时,您正在使用按值传递语义。

Perl也将容纳传递引用。 Perl有一个称为autovivification的功能,其中语言根据需要为您构建必要的脚手架。要使用该样式,您可以编写

my $hashy;
get_date($hashy);

sub get_date {
  my($ref_last) = @_;
  my $duration = '24,0,4';
  @{ $_[0]->{duration} }{qw/ d h m /} = split(/\,/, $duration);
}

请注意,在这种情况下,使用$_[0]直接访问第一个参数,即{em> alias 到$hashy。也就是说,get_date直接修改$hashy

无论哪种方式,我们都会用

打印内容
print "[", join("][" => %{ $hashy->{duration} }), "]\n";

在这种情况下,输出是

的一些排列
[h][0][m][4][d][24]

使用Perl构建复杂的数据结构并不困难,但您必须学习规则。

答案 2 :(得分:0)

这是因为你的哈希引用有一个奇怪的语法。

#!/usr/bin/perl -w
use strict;

my $hashref = {};
get_date($hashref);

print $hashref->{duration}->{d};

sub get_date {
    my ($ref_last) = @_;
    $tmp = '24,0,4';

    ($ref_last->{duration}->{d},
     $ref_last->{duration}->{h},
     $ref_last->{duration}->{m})
            = split(/,/, $tmp);
}

并在您的子例程中使用$ref_last->{duration},而不是$$