【问题标题】:How to check if a Perl hash is defined when it doesn't have any key/value pairs当没有任何键/值对时如何检查是否定义了 Perl 哈希
【发布时间】:2011-07-26 23:58:27
【问题描述】:

我正在尝试找出一种方法来检查是否在模块函数内部的 Perl 脚本中声明了哈希。

给定以下脚本(文件script.pl):

#!/usr/bin/perl -w

use strict;
use checkHash;

our %testHash = ("key"=>"value");

print &checkHash() ? 1 : 0;

连同这个模块(checkHash.pm);

sub checkHash {
    if(%main::testHash) {
        return 1;
    }
    else {
        return 0;
    }
}

1;

在带有OS X v10.6.7 (Snow Leopard) 和 Perl v5.10.0 的 Mac 上运行,checkHash 的返回值为“1”,这是我所期望的。但是,如果我通过更改行从脚本中删除键值对:

our %testHash = ("key"=>"value");

到:

our %testHash = ();

返回值为“0”。我最初的假设是这将是“1”,但是在阅读了我正在使用的测试方法是测试哈希中的大小之后,我明白了为什么这是错误的想法。

是否有一个可以在 checkHash 模块中使用的测试,如果它正在测试的哈希存在,但没有分配任何键,则该测试将返回 true?

【问题讨论】:

  • 为什么?您真正想要完成什么?我之所以这么问,是因为在我的一生中,我从未遇到过需要这样的测试的情况。
  • 我正在构建一个小框架模块,用于设置一些基本的日志记录、调试和其他常用功能。我打算在主脚本中使用用“我们的”定义的散列来来回传递一些信息给框架模块。当我引导框架时,我想检查以确保散列存在。这就是问题的起点。由于主脚本只会定义哈希,但没有值,我无法弄清楚。 (注意:我现在正在考虑调用引导程序来填充哈希,但我仍然想知道这个问题的答案)。
  • 您的问题的答案是一个问题:您认为“定义”是什么意思?听起来您认为它与“声明”的含义相同。它没有。
  • @darch - 是的。我基本上认为“定义”和“声明”是一回事。我试图围绕这一点写作,但显然,这会造成混乱。我将更新这个问题,以帮助将来遇到此问题的任何人解决这个问题。

标签: perl hash


【解决方案1】:

defined() 不是对聚合(数组和散列)的有意义的测试。 perldoc -f defined 有话要说:

不推荐在聚合(散列和数组)上使用“定义”。它 用于报告该聚合的内存是否曾经 分配。 这种行为可能会在 Perl 的未来版本中消失。 您应该改为使用简单的大小测试:

               if (@an_array) { print "has array elements\n" }
               if (%a_hash)   { print "has hash members\n"   }

【讨论】:

  • 该测试的问题是当哈希中没有成员时,当我测试它时它仍然显示为假。即使散列本身的散列是用“my %testHash”或“our %testHash”设置的。我正在尝试找出一种方法,我可以在为其分配新的键/值之前安全地检查哈希是否已经存在,但到目前为止,只有在至少已经存在一个的情况下才能使该测试工作键/值对。
  • 这就是重点:“哈希已经存在”是一个毫无意义的测试。当您需要它们时,或者在严格的情况下,对于词法或不合格的包变量,当您声明它们时,变量就存在了。应该没有必要做你想做的事。
  • 我问的不是很好,但直到我开始得到答案才意识到这一点。我已经更新了问题以尝试更好地提出问题。我真正想要的测试是在模块本身中。这个想法是我正在编写的一个小框架模块可以使用共享哈希与其主脚本进行通信。该框架将检查以确保哈希已声明(未定义,这是我造成很多混乱的地方)并且在尝试使用它之前可用。我还没有做太多构建框架模块的工作,所以这可能有点离谱,但它似乎是有道理的。
  • 那么如果它不检查它是否被声明了会有什么危害呢?
  • 但是在散列中设置标志 使得它存在,没有警告:$main::c{'debug'} = 1;
【解决方案2】:

测试一个给定的符号是否已经被声明几乎肯定是没有用的,执行它的愿望表明存在设计问题。然而,为了完整起见,这里是对词汇和动态符号的测试:

查看词法符号$whoopee 是否已声明:

use Try::Tiny;
my $declared = try { use strict; $whoopee; 1 };

查看是否已声明任何名为 FooPackage::whoopee 的动态符号(包括拼写其名称的哈希 %FooPackage::whoopee):

my $declared = exists $FooPackage::{whoopee};

【讨论】:

  • 你是对的。我根本没有很好地表达我的问题。目标是查看是否已声明散列。我已经更新了问题以试图澄清这一点。顺便说一句,通过从“if(%main::testHash)”更改为“if(exists $main::{testHash})”,我得到了我所期望的行为。由于我对制作自己的模块相对较新,因此很可能会出现设计问题。事实上,当我遇到这个问题时,我改变了我使用的方法,但很高兴知道有一个有效的答案。
【解决方案3】:

perldoc perldata

如果您在标量上下文中评估散列,如果散列为空,则返回 false。如果有任何键/值对,则返回 true;更准确地说,返回的值是一个字符串,由已使用的桶数和分配的桶数组成,用斜杠分隔。

这解释了为什么您的 defined 测试似乎有效。

【讨论】:

    【解决方案4】:

    你可以只数钥匙:

    sub checkHash {
        return ( scalar keys %main::testHash ) ? 1 : 0;
    }
    
    perl -le 'my %h; print ( scalar keys %h ) ? 1 : 0;'
    0
    perl -le 'my %h = (foo=>1); print ( scalar keys %h ) ? 1 : 0;'
    1
    

    【讨论】:

    • 看起来你颠倒了冒号和问号(即应该是“return (scalar keys %main::testHash) ? 1 : 0;”)。但是,这无济于事,因为没有任何键可以计数。它仍然返回 false。
    • 感谢您的关注。它确实有效;我添加了一个例子。 ysth 更好,我可能会这样做。
    • 另一个捕获,看起来像一个额外的“=>1)”进入第一个示例。像“perl -le 'my %h; print (scalar keys %h) ? 1 : 0;'”之类的东西。我正在寻找的技巧是一种进行该测试的方法,但让它返回 1 而不是 0。事实上,当 %h 中没有键时,如果你甚至没有,你会得到相同的结果声明它(例如 perl -le 'print ( scalar keys %h ) ? 1 : 0;')。我正在寻找一个测试,它会告诉我即使没有键存在也会返回 true。 (我可能应该说“初始化”而不是“定义”以避免混淆,但这只是我想到的。
    猜你喜欢
    • 2015-03-28
    • 2018-07-02
    • 2011-05-19
    • 2014-04-06
    • 2012-06-12
    • 2011-01-08
    • 2011-05-30
    • 1970-01-01
    • 2012-02-19
    相关资源
    最近更新 更多