【问题标题】:Pass hash reference in Perl在 Perl 中传递哈希引用
【发布时间】:2011-12-26 11:20:12
【问题描述】:

我正在尝试在 Perl 5.8.8 中传递哈希引用,我知道这应该是一件非常微不足道的事情。我在代码中到处传递哈希值,但由于某种原因,它在这个子例程中不起作用:

sub build_results_hash {
    my %results;
    my $search = $_[0];
    my $json = $_[1];
    my $json_passed = $_[2];

    my $dbh = db_connect(-db=>'ghgs');

    my $db_search = html_db_input($search,$dbh);
    %results = db_hoh(-query=>"SELECT listing_id,MATCH(search) AGAINST($db_search) as relevance FROM search WHERE MATCH(search) AGAINST($db_search) LIMIT 1000",-key=>"listing_id",-dbh=>$dbh);

    if(($json_passed == 1) and ($json ne '[]'))
    {
        narrow_results_hash(\%results,$search,$dbh,$json);
    }

    db_x($dbh);

    return \%results;
}

sub db_hoh {
    # ...
    return %hoh;
}

db_hoh 只返回一个哈希值。问题是当我打电话给narrow_results_hash 并通过%results;这没用。但是,如果我删除了围绕该方法调用的if 语句,那么哈希就可以正常传递了!我不确定是什么导致了这种行为。这是我接收哈希的方式:

sub narrow_results_hash
{
    use JSON::XS;
    my $params = shift;
    my %results = %$params;
    # ...
    print join(',',keys %results), "\n";
    # ...
}

如果我在 build_results_hash 中删除 narrow_results_hash 调用周围的 if 语句,它会打印:“107,99,34”。但是,如果在调用周围出现if 语句,它会打印“HASH(0x7fd61fbf0580)”。

【问题讨论】:

  • “不起作用”的do you mean 到底是什么?另外,请将示例代码缩减为minimal test case。事实上,它不是独立的。
  • 关于“我在代码中到处传递哈希值”,不能将哈希值传递给 subs(只是一个标量列表),并且 subs 不能返回哈希值(只是一个标量列表)。
  • 使用Data::Dumper 查看%results 并确保它是您认为的哈希值。我尝试查找 db_hoh 方法,但在 DBI 文档中找不到它。我怀疑db_hoh 可能正在将 reference 返回到哈希哈希。

标签: perl hash reference subroutine


【解决方案1】:

我的评论太多了。

对于您的实际问题,我们需要了解一些事情才能为您提供帮助。

  1. db_hoh 返回什么、对哈希的引用或键值对列表。
  2. “不起作用”是什么意思?它根本无法工作吗?是不是完成了一些操作,却给你意想不到的结果?

此外,我在您的代码中有一些风格的 cmets。在我看来,您来自 C 世界,对吗?

  1. @_ 解包为列表分配看起来更简洁
  2. 声明 %results 可以等到它被填充
  3. 除非我误解,否则您不需要使用$json_passed,而是可以测试是否定义了$json
  4. narrow子中,可以避免创建$params

这是更新后的代码:

sub build_results_hash {
    my ($search, $json) = @_; 

    my $dbh = db_connect(-db=>'ghgs');

    my $db_search = html_db_input($search,$dbh);
    my %results = db_hoh(
      -query=>"SELECT listing_id,MATCH(search) AGAINST($db_search) as relevance FROM search WHERE MATCH(search) AGAINST($db_search) LIMIT 1000",
      -key=>"listing_id",
      -dbh=>$dbh
    );

    if((defined $json) and ($json ne '[]'))
    {
        narrow_results_hash(\%results,$search,$dbh,$json);
    }

    db_x($dbh);

    return \%results;
}

sub narrow_results_hash
{
    use JSON::XS; #unless you expect this import to be local it looks funny here
    my %results = %{ shift() };
    # ...
}

最后,可能也是最重要的一点,除非html_db_input 正在清理存储在$db_search 中的输入,否则您将面临SQL injection 攻击。看起来你有自己的数据库访问库,但如果你使用DBI,我会这样做:

my $dbh = ...; # connect to db
my $sth = $dbh->prepare('SELECT listing_id,MATCH(search) AGAINST(?) as relevance FROM search WHERE MATCH(search) AGAINST(?) LIMIT 1000');
$sth->execute($db_search,$db_search);
my $results = $sth->fetchall_hashref('listing_id');

这可以防止$db_search 的内容更改您的 SQL 语句。

【讨论】:

  • 回答您最初的问题, 1. db_hoh() 方法末尾的返回行是“return %hoh;” 2. 在我的narrow_results_hash 方法中,我在我的%results 哈希上使用join,就像这样“join(',',keys %results);”如果我打印这个并删除了narrow_results_hash 调用周围的if 语句,我会得到一个类似这样的列表:“107,99,34”。但是,如果调用周围存在 if 语句,我会得到:HASH(0x7fd61fbf0580)。
  • 您使用的是什么版本的 Perl?从版本5.14 开始,许多函数(如keys)可以采用引用以及散列(或数组),它们将被自动取消引用。由于直接打印的结果是 HASH(0xnnnnnnn) 你肯定有一个 hashref 而不是一个散列。看起来好像需要进一步取消引用。
  • 好吧,我想我们需要看到整个narrow_hash_results函数
  • @srchulo:请用您的说明更新问题。通常,通过更新您的帖子而不是回复评论来回应澄清请求。一方面,一个问题应该是可以理解的,无需阅读 cmets。另一方面,SO 是一个 QA 和网站,而不是一个论坛,并且 cmets 不适合(也不适合)讨论。
【解决方案2】:

db_hoh 可能返回哈希引用而不是哈希。尝试使用标量作为结果变量。

my %results;

变成

my $results;

等等……

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-18
    • 2015-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-06
    • 1970-01-01
    相关资源
    最近更新 更多