运算符优先级

3 投票
4 回答
926 浏览
提问于 2025-04-16 12:54

考虑一下这个C#类:

class Node
{
    public Node Next;
}

再看看这两个情况:

        Node A = new Node();
        Node B = A;
        B=(B.Next = new Node());

还有

        Node A = new Node();
        Node B = A;
        B.Next = (B=new Node());

为什么它们会产生相同的结果呢!?
(A)->(B)->Null

我原以为第二种情况会产生一个指向它自身的节点,因为运算符的优先级问题...

JavaPython中也是这样吗? 谢谢

4 个回答

2

在Python中,你不能像你那样把多个赋值放在一起。最右边的值会被赋给它左边的所有变量。

>>> a = (b=42)
  File "<stdin>", line 1
    a = (b=42)
          ^
SyntaxError: invalid syntax
>>> a = b = 42

>>> print a,b
42 42
>>> 

这和你的问题类似

>>> class Node():
...     def __init__(self):
...             self.next = self
... 
>>> n = Node()
>>> n = n.next = Node()
>>> n
<__main__.Node instance at 0x7f07c98eb200>
>>> n.next = n = Node()
>>> n
<__main__.Node instance at 0x7f07c98eb290>
2

C# 在处理赋值时是从左到右进行的。

所以在你的第二个例子中,它首先会“计算”赋值左边的部分(B.Next),然后再去计算右边的部分,最后得到 A 中的 Next 的引用。

你在右边做的任何操作,都是赋值给左边的这个部分。所以如果你在右边改变 B,那就已经太晚了。

如果不是这样的话,

B.Next = (B = null)

就会出现空引用异常,这可不是你所期待的,对吧?

2

这种行为并不是因为运算符的优先级,而是因为Java、Python和C#中有一些规则,规定了表达式的计算顺序。具体来说,在Java、Python和C#中,表达式是从左到右计算的。比如在C和C++中,你写的代码结果可能是未定义的。

你可能听说过这个C语言的难题:

int i = 1;
printf("%d, %d\n", i++, ++i); // what is printed?

在C语言中,结果是未定义的。它可能是1, 3,也可能是2, 2,甚至可能是其他的结果。而在Java、C#和Python中,结果总是1, 3(当然,Python没有前缀或后缀的++运算符)。

运算符的优先级是另一个问题。它定义的是解析树,而不是计算的顺序。

假设你有一种新的语言,里面有二元中缀运算符op1op2。假设你有以下这段代码:

e1 op1 e2 op2 e3

运算符优先级告诉你这段代码是意味着

((e1 op1 e2) op2 e3)

还是意味着

(e1 op1 (e2 op2 e3))

但它并不告诉你e1e2e3的计算顺序。

撰写回答