1

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

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

这个 sub 是从脚本的 main-Part 调用的,如下所示:

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 引用,而 "strict refs" 正在使用"

我已经尝试过了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});
}
4

3 回答 3

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);
}
于 2012-05-23T18:40:18.943 回答
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;
}

最后一行是一个哈希切片,允许您在单个列表分配中为 、 和 键d分配h值。m

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

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]直接访问第一个参数,在这种情况下是别名。$hashy也就是直接get_date修改$hashy

无论哪种方式,假设我们打印内容

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

在这种情况下,输出是一些排列

[h][0][m][4][d][24]

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

于 2012-05-23T18:56:58.237 回答
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},不使用$$.

于 2012-05-23T18:17:30.947 回答