Go中的同时变量赋值与单个变量赋值不同

时间:2016-03-11 22:59:07

标签: go variable-assignment

我的印象是,尽管语法不同,但下面的函数a和函数b在逻辑上是等价的。但是,它们不是,我不明白它们之间的区别。

在我看来,他们都在分配:

  • x的值为变量z,
  • y的值为变量x和
  • 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
}

3 个答案:

答案 0 :(得分:5)

分配可以被认为是“原子”操作。也就是说,认为=左侧的所有值都被“冻结”,直到所有操作都完成为止是有用的。

考虑以下计划:

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
}

如果没有这种“冻结”行为,2x都会得到y可能不是你所期望的码。与“采用级联”方法相比,它也可能 更容易推理出这种“冻结”行为的语义。

答案 1 :(得分:2)

  

The Go Programming Language Specification

     

Assignments

     

左边的操作数必须等于数量   右边的表达式,每个都必须是单值的,而且   右边的第n个表达式被赋值给第n个操作数   左:

one, two, three = '一', '二', '三'
     

空白标识符提供了忽略右侧值的方法   在作业中:

_ = x       // evaluate x but ignore it
x, _ = f()  // evaluate f() but ignore second result value
     

转让分两个阶段进行。一,索引的操作数   表达式和指针间接(包括隐式指针)   左边的选择器中的间接和)上的表达式   权利都按照通常的顺序进行评估。第二,任务   按从左到右的顺序进行。

元组赋值是两阶段赋值。首先,左侧的索引表达式和指针间接操作(包括选择器中的隐式指针间接)的操作数和右侧的表达式都按通常的顺序进行评估。其次,分配按从左到右的顺序进行。

例如,

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

答案 2 :(得分:2)

简单的答案是因为它是y的所有一个陈述,2的值在评估x+y时尚未更新为y。 IE在右侧的表达式在任何赋值之前进行评估。在另一种情况下,所有事情都是一步一步发生的,所以of 2的价值已经更新为{{1}}而你得到了4。

出于学术目的的有趣问题,现实生活中的可怕代码所以请不要在真实的程序中写出类似的东西。