Go 中的同时变量赋值与单独变量赋值不同
Simultaneous variable assignment in Go different from individual variable assignment
我的印象是,尽管语法不同,但下面的函数 a 和函数 b 在逻辑上是等价的。但是,它们不是,我不明白它们之间的区别。
在我看来,他们都在分配:
- x到变量z的值,
- 变量x的y值,
- x+y 对变量 y 的值。
谁能帮我解开我对多变量赋值以及函数a和函数b的逻辑区别的误解?
package main
import "fmt"
func a() (int, int, int) {
x:=1
y:=2
z:=3
z = x
x = y
y = x+y
return x, y, z
}
func b() (int, int, int) {
x:=1
y:=2
z:=3
z, x, y = x, y, x+y
return x, y, z
}
func main() {
fmt.Println(a()) // prints 2 4 1
fmt.Println(b()) // prints 2 3 1
}
The Go Programming Language Specification
the number of operands on the left must equal the number of
expressions on the right, each of which must be single-valued, and the
nth expression on the right is assigned to the nth operand on the
left:
one, two, three = '一', '二', '三'
The blank identifier provides a way to ignore right-hand side values
in an assignment:
_ = x // evaluate x but ignore it
x, _ = f() // evaluate f() but ignore second result value
The assignment proceeds in two phases. First, the operands of index
expressions and pointer indirections (including implicit pointer
indirections in selectors) on the left and the expressions on the
right are all evaluated in the usual order. Second, the assignments
are carried out in left-to-right order.
元组赋值是两阶段赋值。首先,左边的索引表达式和指针间接(包括选择器中的隐式指针间接)和右边的表达式的操作数都按通常的顺序求值。其次,赋值是按照从左到右的顺序进行的。
例如,
package main
import "fmt"
func a() (int, int, int) {
x := 1
y := 2
z := 3
// phase 1
tx := x
ty := y
// phase 2
z = tx
x = ty
y = tx + ty
return x, y, z
}
func b() (int, int, int) {
x := 1
y := 2
z := 3
z, x, y = x, y, x+y
return x, y, z
}
func main() {
fmt.Println(a())
fmt.Println(b())
}
输出:
2 3 1
2 3 1
简单的答案是因为它是一个语句,并且 y
的值在计算 x+y
时尚未更新为 2
。 IE 右侧的表达式在任何赋值之前进行评估。在另一种情况下,一切都一步一步发生,所以 y
的值已更新为 2
,你得到四个。
出于学术目的有趣的问题,现实生活中的糟糕代码所以请不要在真实程序中编写类似的东西。
赋值可以看作是一个"atomic"操作。也就是说,认为 =
左侧的所有值都是 "frozen" 直到所有操作都完成是有用的。
考虑以下程序:
package main
import "fmt"
func swap() (int, int) {
x := 1
y := 2
x, y = y, x
return x, y
}
func main() {
fmt.Println(swap()) // prints 2 1
}
如果没有这种 "freezing" 行为,x
和 y
都会得到 2
,可能 不会您对代码的期望。与采用 "cascading" 方法相比,可能 更容易推断此 "freezing" 行为的语义。
我的印象是,尽管语法不同,但下面的函数 a 和函数 b 在逻辑上是等价的。但是,它们不是,我不明白它们之间的区别。
在我看来,他们都在分配:
- x到变量z的值,
- 变量x的y值,
- x+y 对变量 y 的值。
谁能帮我解开我对多变量赋值以及函数a和函数b的逻辑区别的误解?
package main
import "fmt"
func a() (int, int, int) {
x:=1
y:=2
z:=3
z = x
x = y
y = x+y
return x, y, z
}
func b() (int, int, int) {
x:=1
y:=2
z:=3
z, x, y = x, y, x+y
return x, y, z
}
func main() {
fmt.Println(a()) // prints 2 4 1
fmt.Println(b()) // prints 2 3 1
}
The Go Programming Language Specification
the number of operands on the left must equal the number of expressions on the right, each of which must be single-valued, and the nth expression on the right is assigned to the nth operand on the left:
one, two, three = '一', '二', '三'
The blank identifier provides a way to ignore right-hand side values in an assignment:
_ = x // evaluate x but ignore it x, _ = f() // evaluate f() but ignore second result value
The assignment proceeds in two phases. First, the operands of index expressions and pointer indirections (including implicit pointer indirections in selectors) on the left and the expressions on the right are all evaluated in the usual order. Second, the assignments are carried out in left-to-right order.
元组赋值是两阶段赋值。首先,左边的索引表达式和指针间接(包括选择器中的隐式指针间接)和右边的表达式的操作数都按通常的顺序求值。其次,赋值是按照从左到右的顺序进行的。
例如,
package main
import "fmt"
func a() (int, int, int) {
x := 1
y := 2
z := 3
// phase 1
tx := x
ty := y
// phase 2
z = tx
x = ty
y = tx + ty
return x, y, z
}
func b() (int, int, int) {
x := 1
y := 2
z := 3
z, x, y = x, y, x+y
return x, y, z
}
func main() {
fmt.Println(a())
fmt.Println(b())
}
输出:
2 3 1
2 3 1
简单的答案是因为它是一个语句,并且 y
的值在计算 x+y
时尚未更新为 2
。 IE 右侧的表达式在任何赋值之前进行评估。在另一种情况下,一切都一步一步发生,所以 y
的值已更新为 2
,你得到四个。
出于学术目的有趣的问题,现实生活中的糟糕代码所以请不要在真实程序中编写类似的东西。
赋值可以看作是一个"atomic"操作。也就是说,认为 =
左侧的所有值都是 "frozen" 直到所有操作都完成是有用的。
考虑以下程序:
package main
import "fmt"
func swap() (int, int) {
x := 1
y := 2
x, y = y, x
return x, y
}
func main() {
fmt.Println(swap()) // prints 2 1
}
如果没有这种 "freezing" 行为,x
和 y
都会得到 2
,可能 不会您对代码的期望。与采用 "cascading" 方法相比,可能 更容易推断此 "freezing" 行为的语义。