Perl哈希没有按预期初始化

时间:2014-03-24 16:46:52

标签: perl

我从Perl哈希(关联数组)获得意外结果。

我正在尝试从CGI帖子中填充它,其中可能缺少某些表单值。

use strict;
use Data::Dumper;
use CGI;

my $cgi = new CGI;

my %data = (
        'key1' => $cgi->param('fkey1'),
        'key2' => $cgi->param('fkey2'),
        'key3' => $cgi->param('fkey3'),
        'key4' => $cgi->param('fkey4'),
        'key5' => $cgi->param('fkey5'),
        'key6' => $cgi->param('fkey6'),
        'key7' => $cgi->param('fkey7'),
        'key8' => $cgi->param('fkey8'),
        'key9' => $cgi->param('fkey9'),
        'key0' => $cgi->param('fkey0'),
    );

print "Content-type: text/html\n\n<pre>";
print Dumper \%data;

my $fkey1 = $cgi->param('fkey1');
my $fkey2 = $cgi->param('fkey2');
my $fkey3 = $cgi->param('fkey3');
my $fkey4 = $cgi->param('fkey4');
my $fkey5 = $cgi->param('fkey5');
my $fkey6 = $cgi->param('fkey6');
my $fkey7 = $cgi->param('fkey7');
my $fkey8 = $cgi->param('fkey8');
my $fkey9 = $cgi->param('fkey9');
my $fkey0 = $cgi->param('fkey0');


my %data2 = (
        'key1' => $fkey1,
        'key2' => $fkey2,
        'key3' => $fkey3,
        'key4' => $fkey4,
        'key5' => $fkey5,
        'key6' => $fkey6,
        'key7' => $fkey7,
        'key8' => $fkey8,
        'key9' => $fkey9,
        'key0' => $fkey0,
    );

print "Content-type: text/html\n\n<pre>";
print Dumper \%data2;

%数据完全错误。我必须像%data2那样做。输出结果如下:

$VAR1 = {
     'key9' => 'key0',
     'key5' => 'key6',
     'key1' => 'key2',
     'key7' => 'key8',
     'key3' => 'key4'
   };

$VAR1 = {
    'key9' => undef,
    'key5' => undef,
    'key6' => undef,
    'key8' => undef,
    'key0' => undef,
    'key3' => undef,
    'key2' => undef,
    'key1' => undef,
    'key4' => undef,
    'key7' => undef
  };

因此,如果$ cgi-> param('fkey1')为undef,它会跳过该值并使用下一个键作为值。为了让%数据有效,我还需要做些什么吗?

3 个答案:

答案 0 :(得分:8)

此问题是由于param在列表上下文与标量上下文中的行为方式所致。

在标量上下文中,如果参数不存在,param将返回undef。在列表上下文中,它返回一个空列表。所以假设你有一个像这样的哈希初始化:

my %data = ( foo => $cgi->param( 'foo' ),
             bar => $cgi->param( 'bar' ),
             baz => $cgi->param( 'baz' ) );

并假设参数bar不存在。由于在列表上下文中调用param,因此传递给哈希初始化的列表最终看起来像这样:

( 'foo', 'foovalue', 'bar', 'baz', 'bazvalue' )

请注意bar键之后没有任何内容,因为那里返回了一个空列表。

要解决此问题,您可以强制所有对param的调用进入标量上下文:

my %data = ( foo => scalar $cgi->param( 'foo' ),
             bar => scalar $cgi->param( 'bar' ),
             baz => scalar $cgi->param( 'baz' ) );

现在列表将如下所示:

( 'foo', 'foovalue', 'bar', undef, 'baz', 'bazvalue' )

世界上的一切都是对的。

答案 1 :(得分:4)

CGI.pm已经提供了fetch the parameter list as a hash使用Vars方法的方法:

use CGI;

my $q = CGI->new;
my %params = $q->Vars;

多值参数作为由空字符\0分隔的打包字符串返回。您必须拆分字符串以获取各个值。

答案 2 :(得分:3)

一种方法是为空值提供默认值,因为这会强制param在标量上下文中返回。它还具有修复使用未初始化的值警告的双重好处:

my %data = (
    'key1' => $cgi->param('fkey1') // '',
    'key2' => $cgi->param('fkey2') // '',
    'key3' => $cgi->param('fkey3') // '',
    'key4' => $cgi->param('fkey4') // '',
    'key5' => $cgi->param('fkey5') // '',
    'key6' => $cgi->param('fkey6') // '',
    'key7' => $cgi->param('fkey7') // '',
    'key8' => $cgi->param('fkey8') // '',
    'key9' => $cgi->param('fkey9') // '',
    'key0' => $cgi->param('fkey0') // '',
);

但是,如果此代码不仅仅是一个示例,它可以简化为:

my %data = map {"key$_" => $cgi->param("fkey$_") // ''} (0..9);

顺便说一句,如果您想测试何时在数组上下文中调用类似param的函数,可以使用以下代码:

sub test {
    if (wantarray) {
        print "<array>\n"; return ();
    } else {
        print "<scalar> - $_[0]\n"; 
        return undef;
    }
}

my %h = (
    key1 => test('array'),
    key2 => scalar test('scalar'),
    key3 => test('logical defined-or') // '',
    key4 => test('logical or') || '',
    key5 => test('concat') . '',
);

输出显示上述任何方法都可以强制标量上下文。我虽然只使用scalar//

<array>
<scalar> - scalar
<scalar> - logical defined-or
<scalar> - logical or
<scalar> - concat