Perl:无法将“on-the-fly”数组传递给sub

时间:2010-07-19 15:20:59

标签: perl arrays

strftime(),根据cpan.org:

print strftime($template, @lt);

我只是想不出这个正确的Perl代码配方。它会在我调用strftime()时报告错误:

...
use Date::Format;
...
sub parse_date {
 if ($_[0]) {
  $_[0] =~ /(\d{4})/;
  my $y = $1;
  $_[0] =~ s/\d{4}//;
  $_[0] =~ /(\d\d)\D(\d\d)/;
  return [$2,$1,$y];
  }
 return [7,7,2010];
 }

foreach my $groupnode ($groupnodes->get_nodelist) {
    my $groupname = $xp->find('name/text()', $groupnode);
    my $entrynodes = $xp->find('entry', $groupnode);
    for my $entrynode ($entrynodes->get_nodelist) {
        ...
        my $date_added = parse_date($xp->find('date_added/text()', $entrynode));
        ...
        $groups{$groupname}{$entryname} = {...,'date_added'=>$date_added,...};
        ...
        }
    }
...

my $imday = $maxmonth <= 12 ? 0 : 1;
...

while (my ($groupname, $entries) = each %groups) {
    ...
    while (my ($entryname, $details) = each %$entries) {
        ...
        my $d = @{$details->{'date_added'}};
        $writer->dataElement("creation", strftime($date_template, (0,0,12,@$d[0^$imday],@$d[1^$imday]-1,@$d[2],0,0,0)));
        }
    ...
    }
...

如果我使用()通过strftime()传递所需的数组,我得到: arg 2到Date的类型:: Format :: strftime必须是./blah.pl第87行的数组(不是列表),靠近“))”

如果我使用[]传递所需的数组,我得到: arg 2到Date的类型:: Format :: strftime必须是./blah.pl第87行的数组(不是匿名列表([])),靠近“])”

如何将数组动态传递给Perl中的sub?这可以通过PHP,Python,JS等轻松完成。但我无法用Perl来理解它。

编辑:我将代码缩减到这几行,我仍然遇到了完全相同的问题:

#!/usr/bin/perl

use warnings;
use strict;
use Date::Format;

my @d = [7,13,2010];
my $imday = 1;
print strftime( q"%Y-%m-%dT12:00:00", (0,0,12,$d[0^$imday],$d[1^$imday]-1,$d[2],0,0,0));

4 个答案:

答案 0 :(得分:7)

如果需要数组并且您有一个临时列表,则需要实际创建一个数组。它不需要是一个单独的变量,你可以这样做:

strftime(
    $date_template,
    @{ [0,0,12,$d[0^$imday],$d[1^$imday],$d[2],0,0,0] }
);

我不知道为什么Date :: Format会让你受到这种可怕的影响,而不仅仅是期望多个标量参数;似乎毫无意义(与其他模块如何实现strftime相反)。 Graham Barr通常设计出比这更好的接口。也许它可以追溯到原型仍然是一般用途的酷想法。

答案 1 :(得分:3)

要将列表用作字符串插值的匿名数组,您可以编写

print "@{[1, 2, 3]}\n";

获取

1 2 3

同样的技术为Date::Format::strftime的时髦原型提供了一种解决方法:

print strftime(q"%Y-%m-%dT12:00:00",
               @{[0,0,12,$d[0^$imday],$d[1^$imday]-1,$d[2],0,0,0]});

输出:

1900-24709920-00T12:00:00

答案 2 :(得分:2)

通常,很容易将“即时”数组传递给Perl子程序。但是Date::Format::strftime是一个特殊情况,特殊原型($\@;$)不允许“列表”参数或“列表赋值”参数:

strftime($format, (0,0,12,13,7-1,2010-1900));      # not ok
strftime($format, @a=(0,0,12,13,7-1,2010-1900));   # not ok

解决方法是必须使用数组变量调用strftime

my @time = (0,0,12,13,7-1,2010-1900);   # note: @array = ( ... ), not [ ... ]
strftime($format, @time);

答案 3 :(得分:0)

我再次看了一下,我看到了这段代码中的真正问题:

my $d = @{$details->{'date_added'}};
    $writer->dataElement("creation", strftime($date_template, (0,0,12,@$d[0^$imday],@$d[1^$imday]-1,@$d[2],0,0,0)));

具体来说,@{$details->{'date_added'}}是一个解除引用。但是你将它分配给一个标量变量,你不需要在它下面的行中取消引用:

my @d = @{$details->{'date_added'}};
    $writer->dataElement("creation", strftime($date_template, (0,0,12,$d[0^$imday],$d[1^$imday]-1,$d[2],0,0,0)));

我为您的参考@d创建了一个常规数组,并将其作为常规数组($d[ ... ]而不是@$d[ ... ])进行访问。