为什么可以评估`定义的$ x&&布尔上下文中的$ x`?

时间:2012-09-14 06:11:37

标签: perl operators boolean

my $target_type = (defined($item->{target_type}) && $item->{target_type}) 
                ? $item->{target_type} 
                : "";

my $target_id   = (defined($item->{target_id}) && $item->{target_id})
                ? $item->{target_id} 
                : "";

为什么开发人员在几乎相同的条件下使用&&

6 个答案:

答案 0 :(得分:6)

显然他是腰带和吊带类型。 (defined($x) && $x)几乎等同于$x,因为undef是假的。 (不同之处在于如果$xundef,那么(defined($x) && $x)将是Perl的特殊假值,已定义,但在这种情况下没有区别。)可能存在曾经是一个不同的条件(如$x > 0),defined测试是必要的,以避免有关未初始化值的警告。然后有人删除了这个条件,并没有考虑删除现在不必要的defined

使用(defined($x) && $x)(作为onon15 points out)的另一个原因是强调未来的维护程序员可能未定义$x。就个人而言,我会对此进行评论,但TIMTOWTDI

答案 1 :(得分:2)

尽管&& amp;的右侧可以单独使用,我已经多次看到这种用法作为人类读者的语义暗示,$item->{target_type}可能没有被定义。

因此,即使可以删除LHS并保持相似的行为,维护者也可能很容易误以为不需要检查是否定义了值。 (除非在紧密的循环中,额外评估的成本可以忽略不计,甚至在循环内部,它很可能通过解释器中的优化来删除。)

答案 2 :(得分:2)

非常简短的回答:这是为了避免在较旧的perls中使用“未初始化值”警告并在此情况下分配默认定义值。在v5.10及更高版本中,您将使用defined-or运算符:

 $scalar //= "";

答案 3 :(得分:1)

&&是一个“逻辑短路”运算符。首先,他正在测试$item->{targ_type}的定义。如果且仅当它被定义时(即&&的左侧为真),则他测试以查看$item->{target_type}是否包含真值。如果两个条件均为真,则$target_type(以及之后的$target_id)会分配$item->{target_type}$item->{target_id}中的值。如果其中一个条件为false,则分配一个空字符串。

更新:尝试阅读提出构造的程序员的想法:也许代码以导致这种情况的方式发展,并且程序员没有想到它足够长的时间来认识到它是不必要的。也许程序员对于定义,真理,虚假以及Perl中哪些类型的值是“错误”之间的区别是不安全的。

答案 4 :(得分:1)

回答你的问题需要精神阅读,但这里有几个原因按概率排序:

  1. 作者不是Perl程序员,因此对undef的真实性感到不安,defined undef && undef评估""并使表达的其余部分没有实际意义,或两者兼而有之
  2. 代码看到了一个修订版,删除了需要defined测试才能正常运行的内容,例如defined $x && $x ne ''defined测试是从编辑遗留下来的,对维护者来说是负面价值。
  3. 作者希望强调该元素可能是undef,因此明确地对其进行了测试。有更好的方法可以做到这一点,不会让未来的读者猜测出意图可能是什么。比方说,评论。
  4. 如果已定义,$item->{target_type}可能包含一个带有重载布尔转换的对象,计算成本很高,而且您正在寻找一种自我挫败的微优化。这种情况极不可能发生。但是很有趣。

答案 5 :(得分:0)

情况并非如此。

首先,他测试定义性

defined($item->{target_type})

使用未定义的值进行操作时,某些操作没有意义。

在第二种情况下,他会测试真值或假值

$item->{target_type}

但是,由于undef是假值,第二次测试涵盖两种情况。

在某些情况下,需要类似的模式,例如在测试参考文献的内容时。

my $ref1 = "true";
my $ref2 = \("true");

if (ref $ref1 eq 'SCALAR' and $$ref1) {
  # This does not get executed
}
if (ref $ref2 eq 'SCALAR' and $$ref2) {
  # This does get executed
}