如何比较Perl引用?

31
我想检查两个引用是否指向同一对象。似乎我可以简单地使用
if ($ref1 == $ref2) { 
 # cheap numeric compare of references
 print "refs 1 and 2 refer to the same thing\n";
}

perlref 所述,但我模糊地记得看到过使用某个函数来实现同样的目的。有没有任何理由我不应该使用简单的数字相等性测试?

请注意,我只想知道引用是否指向完全相同的对象。我不寻找比较对象内容的方法。

3个回答

27

默认情况下,引用被数字化为它们的地址。对于每个引用来说,这些引用地址都是唯一的,因此在相等性检查中通常可以使用它们。

但是,在您展示的片段中,您首先必须确保$ref1$ref2都实际上是引用。否则,由于常规标量包含引用地址,可能会得到不正确的结果。

此外,并没有什么保证参考文献数字化为它们的地址。例如,对象可以使用重载来影响它们在不同上下文中返回的值。

比直接比较引用的数值相等更可靠的方法是,在确保两侧都是引用之后,使用由Scalar::Util提供的refaddr函数。


2
如果你正在使用一个带有数字化(0+)重载或==重载(可能是通过<=>)的类,那么你实际上可能想要它被拦截的自定义相等性。没有提到这些考虑因素就发表一般性声明似乎过于简单化。话虽如此,我想不出有多少情况下模块函数所采取的代码路径会是你试图挤出每一丝性能的关键路径。但如果是这样,当然你会想使用正常的== - tchrist
同意。这就是为什么你的回答提到了这一点,我给你点了赞。有很多情况下我们可能想要比较两个东西是否相等,而使用哪种相等性应该根据每个具体情况来考虑。尽管如此,问题还是非常具体的,因此得到了一个具体的答案。 - rafl
它值得一个特定的答案,这也是你得到我点赞的原因。☺ - tchrist

17

你要查找的函数是来自于Scalar::Util的refaddr函数(在确保所比较的值确实为引用后使用):

use Scalar::Util 'refaddr';

if ($obj1 and ref($obj1) and $obj2 and ref($obj2) and
    refaddr($obj1) == refaddr($obj2))
{
    # objects are the same...
}

2
cpan/List-Util/lib/Scalar/Util/PP.pmrefaddr() 函数为了确定引用的真实地址所采取的非凡措施仅被 blessed() 函数用于查找包名的措施所超越。 - tchrist
4
幸运的是,List-Util分发和它包含的Scalar::Util模块都是核心模块,并且核心是使用C编译器构建的,因此几乎每个人都可以享受使用C版本的Scalar::Util::refaddr的奢侈,这基本上只需要一个标志检查和解除引用操作。 - rafl
实际上,在mktables代码中有一个测试,用于判断它是否是快速的Scalar::Util。我应该记住它可能只是一个C调用。 - tchrist
3
唯一提供代码片段的答案得到了加1分。你其实可以节省2个检查,因为ref($obj)的值即使$objundef也会被求值为假。所以也许可以去掉$obj1$obj2的条件判断? - Daniel Böhmer

8
我假设你关于平等测试的便宜(=快速)的评论是有原因的。鉴于这一点,您应该继续使用廉价的相等性测试。它非常快,比eq快得多,更不用说任何深度比较了。
一个直接或间接重载==运算符的对象可能会篡夺测试以满足自己的目的。但是,如果它确实在这样做,您甚至可能更喜欢它的中介答案。
您采取的方法可能取决于您对对象类的了解。适用于一般情况的方法并不总是针对特定情况最优的。您了解某些事物的信息越多,就越能优化它-反之亦然。
因此,如果您知道您没有使用可适用的类,则没有理由引入非内置库函数,并且有充分的理由不这样做。如果您不知道重载的情况,或者您知道重载的情况并且不希望其适用,则可能采用缓慢的方法。
只要您了解重载问题,将其中一个方法视为正确的,另一个方法视为错误的是错误的。每种方法都有其目的。如果总是做您正在做的事情是错误的,那么该操作将被禁止或至少会受到警告。
您会注意到它没有被标记为这样。

2
你会认为所有的踩票者都有勇气实际上拼出他们认为我说错了什么。但是他们没有。所以显然他们更喜欢匿名的暗箭,而不是理性的讨论。如果你不能证明你的投票,请不要进行投票。 - tchrist
2
我对你发布的内容没有任何问题(也没有点踩),但我认为有趣的是,许多帖子要求解释点踩的原因,但不要求解释点赞的原因。我不会花时间为我每天给出的20个点赞进行辩解。 - friedo
5
如果你认为我是正确的,那么知道你认为我是正确的就足够了。即使如此,如果有一个特别值得强调的观点,“+1”评论是相当常见的。如果你认为我是错误的,我想知道为什么你认为我是错的,这样我可以澄清我的陈述,驳斥你的反对意见,甚至可能(可怕的恐惧)意识到你的反对意见是准确的,并从中学到东西。这就是为什么我至少希望在负投票下有评论,但对于正投票来说,我不在乎。 - Dave Sherohman

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