我声明了以下子(实际上,值来自数据库 - 所以我简化了它):
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});
}
答案 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,可让您在单个列表分配中为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]
直接访问第一个参数,即{em> alias 到$hashy
。也就是说,get_date
直接修改$hashy
。
无论哪种方式,我们都会用
打印内容print "[", join("][" => %{ $hashy->{duration} }), "]\n";
在这种情况下,输出是
的一些排列[h][0][m][4][d][24]
使用Perl构建复杂的数据结构并不困难,但您必须学习规则。
man perlref
perldoc perldsc
perldoc perllol
答案 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}
,而不是$$
。