19

可能的重复:
为什么 Java 没有条件与和条件或运算符的复合赋值版本?(&&=, ||=)
为什么“&&=”运算符不存在?

今天上班写了如下LOC(b和b1的真实身份保密:)

b &&= b1; // meaning b = b && b1; 

我盯着它看了几秒钟,意识到不存在这样的运营商。可以肯定的是,我点击了编译,但它失败了。为了确定我参考了标准。

没有这样的运营商是否有具体原因?我能想到一些:

  1. b &&= b1b = b && b1由于 && 的短路评估,可能不等效。
  2. &&= 很丑
  3. &&= 很少需要

我并不是说拥有这样的运营商会非常有用,不。我也没有声称上述三个原因中的任何一个或全部都不足以避免创建该运算符。我的问题如下:我正在监督是否有更严重的原因?

4

6 回答 6

13

我不知道为什么这个问题和一些答案都提到相应逻辑运算符的短路行为是一个潜在问题。

&&=定义和运算符绝对没有与短路相关的问题||=。它们应该用+=和 其他类似的运算符统一定义,这意味着a &&= b应该等价于a = a && b,但在版本a中只被评估一次。&&=这反过来意味着如果最初为零,b则根本不评估。a简单的。

因此,它们在语言中不存在的唯一原因是,“只是因为”。

于 2010-10-18T21:32:08.977 回答
9

我以前也想要它们。我怀疑丑陋本身就是决定因素,短路行为是我迄今为止听到的反对它们的最佳论据。

另一个促成因素是 C 被设计为接近金属操作,几乎所有操作符都直接对应于主要架构中的指令。我认为没有直接实现的 x86、PPC 等指令b &&= b1;

于 2010-10-18T20:21:03.343 回答
2

运营商不存在的最大原因可能是 K&R 没有想到任何吸引人的方式来定义它们。我有时也想要一个 ->= 运算符(ptr->=next 相当于 ptr = ptr->whatever)。

我认为 &&= 的一个问题是,以下哪个最有用或应该是哪个并不明显:

  如果 (lhs && rhs) lhs = 1; 否则 lhs = 0;
  如果 (!rhs) lhs = 0; 否则 lhs = !(!lhs));
  如果 (lhs && !rhs) lhs = 0;
  如果 (!rhs) lhs = 0;
第一个变体是语法中最清楚地暗示的变体,但从实际的角度来看,如果两个项都不为零,则将左侧单独保留通常比将其设置为“1”更有用。

顺便说一句,我经常希望逗号运算符的变体可以评估左侧,保存值,然后评估右侧,并返回左侧的值。相当于:

int foo(int p1, int p2) 返回 p1;
除非适用于任何类型(p2 不必与 p1 类型相同,并且可以为 void),并且具有保证的从左到右的评估顺序。对于诸如使用非单位步骤的后增量索引之类的事情会非常方便,例如 arr[ptr ~, ptr+=2]; 或者对于某些类型的数据交换操作,例如,var1 = (var2 ~, var2=var1); 等等

于 2010-10-18T21:01:11.160 回答
2

因为结果a && b总是0or ,所以我认为对 C99类型1的解释只会是明确的。_Bool由于在创建 C 时它不存在,因此不包括该运算符。现在没有人能轻易地在 C 中添加另一个运算符,因为这会对所有现有的解析器产生影响。

于 2010-10-19T08:43:11.333 回答
1

就我个人而言,我会投票支持你提出的第一个理由。布尔运算符具有短路语义,如果将其转换为赋值运算符,这将导致一些非常棘手的情况。要么您不再使它们短路,要么您创建了一些奇怪的“可选”赋值运算符(仅在 LHS 上的值已经非零时才执行右侧的操作并在结果中赋值)。无论哪种方式,您都会创建微妙的错误,因为人们会期待其他行为。

于 2010-10-18T20:29:21.723 回答
0

编辑:语言错误,但仍然适用

我同意您的三个原因,尽管在编写自定义反序列化例程时,我曾对缺少此运算符感到遗憾。在一些不正确序列化的对象并不是真正“异常”的情况下(并且为了防止 C# 中非常常见的故障导致异常开销),我将使用布尔返回值来表示反序列化操作是否成功。

这段代码完全是理论上的,Nested1、Nested2 和 Nested3 都是结构体:

public struct ComplexStruct
{
    private Nested1 nested1;
    private Nested2 nested2;
    private Nested3[] nested3;

    public bool Read(Reader reader)
    {
       bool ret = true;
       int nested3Length = 0;

       ret &&= nested1.Read(reader);
       ret &&= nested2.Read(reader);
       ret &&= reader.ReadInt32(ref nested3Length);

       for(int i = 0; (ret && i < nested3Length); i++)
       {
          ret &&= nested3[i].Read(reader);
       }

       return ret;
    }
}
于 2010-10-18T20:20:48.967 回答