如何在Perl中测试“something”是否为哈希?

35

我从另一个函数接收到哈希的哈希,其中一些元素可能是另一个哈希。我如何测试某个元素是否为哈希?


2
可能是如何判断Perl变量中存储的值的类型?的重复问题。 - Ether
4个回答

52

根据你的需要,你需要使用 ref 或者是 reftype(位于核心模块Scalar::Util中)。如果引用是一个对象,ref会返回该对象的类而不是底层引用类型,reftype总是会返回底层引用类型。

if (ref $var eq ref {}) {
   print "$var is a hash\n";
}

use Scalar::Util qw/reftype/;

if (reftype $var eq reftype {}) {
    print "$var is a hash\n";
}

3
你熟悉单词 "tf" 吗?它类似于 "if",但更为强调。 - Chas. Owens
1
那么,if 的更强版本?还有更弱的版本吗? - brian d foy
2
我以为“emphatic if”是“iiiif”,或者用Perl的风格写作:'i'x$n.'f'(当$n > 1时)。 - Mike Ellery
perldoc'ref':_如果所引用的对象已被结构化到一个包中,那么该包名称将被返回。但是不要使用它,因为现在被认为是“不良行为”。其中一个原因是,对象可能正在使用名为Regexp或IO甚至HASH的类。此外,ref不考虑子类,而isa则考虑。相反,使用布尔检查的blessed(在Scalar :: Util模块中),使用特定类检查的isa和进行类型检查的reftype(也来自Scalar :: Util)。_ - David Tonhofer

20

使用ref函数:

ref($hash_ref) eq 'HASH' ## $hash_ref is reference to hash
ref($array_ref) eq 'ARRAY' ## $array_ref is reference to array

ref( $hash{$key} ) eq 'HASH' ## there is reference to hash in $hash{$key}

2
这个测试不适用于类似哈希的对象:$r = {}; bless $r, "fail"; print ref $r - mob
这里也存在一些误报。$array = []; bless $array, 'HASH'; print ref $array; 打印出 HASH。不过你永远都不应该这样做。 - Greg Nisbet

5

我一直使用isa,但是如果被测试的东西不是一个对象(或者可能不是一个对象),你需要将其作为函数调用UNIVERSAL::isa

if ( UNIVERSAL::isa( $var, 'HASH' ) ) { ... }

3
use Params::Util qw<_HASH _HASH0 _HASHLIKE>;

# for an unblessed hash with data
print "$ref is a hash\n" if _HASH( $ref ); 
# for an unblessed hash empty or not
print "$ref is a hash\n" if _HASH0( $ref ); 
# for a blessed hash OR some object that responds as a hash*
print "$ref is hashlike\n" if _HASHLIKE( $ref );

* 通过overload实现

最后一个可能不需要。

参见Params::Util


2
Params::Util::_HASHLIKE 调用 Scalar::Util::reftype,但它还检查其参数是否重载了哈希解引用运算符——这可以检测到那些即使不是真正的哈希引用也可以假装成哈希引用的对象。 - mob
@mobrule:是的,我知道。我只是觉得提供两个选择会促使他点击链接查看差异。我添加了一条注释说他可能不需要它。 - Axeman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接