Golang 第二章 4.赋值

  • By v2ray节点

  • 2024-08-13 10:30:47

  • 评论

变量中保存的值是通过赋值语句更新的。在其最简单的形式中,赋值语句在等号的左边是一个变量,而在等号的右边是一个表达式。

x=1 // 命名变量
*p = true // 间接变量
person.name = "bob" // 结构字段
count[x] = count[x] * scale // 数组或切片或map元素

每个算术和按位二元运算符都有一个相应的赋值运算符,例如,最后的语句可以重写为:

count[x] *= scale

这使我们不必重复(和重新计算)变量的表达式。数值变量还可以通过 ++ 和 -- 语句进行递增和递减:

v := 1
v++ // same as v = v + 1; v becomes 2
v-- // same as v = v - 1; v becomes 1 again


1、元组赋值

另一种形式的赋值称为元组赋值,它允许同时给多个变量赋值。在更新变量之前,右侧的所有表达式都会被计算。这种形式在一些变量同时出现在赋值两边时最为有用,例如在交换两个变量的值时:

x, y = y, x
a[i], a[j] = a[j], a[i]

或者在计算两个整数的最大公约数(GCD)时:

func gcd(x, y int) int {
	for y != 0 {
		x, y = y, x%y
	}
	return x
}

或者在迭代计算第 n 个斐波那契数时:

func fib(n int) int {
	x, y := 0, 1
	for i := 0; i < n; i++ {
		x, y = y, x+y
	}
	return x
}

元组赋值还可以使一系列简单的赋值变得更为紧凑,

i, j, k = 2, 3, 5

不过作为一种风格,如果表达式很复杂,还是避免使用元组形式;一系列独立的语句更容易阅读。某些表达式,例如调用一个有多个返回值的函数,会生成多个值。当这样的调用用在赋值语句中时,左边的变量数量必须与函数返回的结果数量相等。


f, err = os.Open("foo.txt")	// 函数调用返回两个值

通常,函数使用这些附加结果来指示某种错误,可能通过返回一个错误(如调用 os.Open 时),或者返回一个布尔值,通常叫做 ok。正如我们将在后续章节中看到的,有三个运算符有时也会这样行为。如果在赋值中期望两个结果时出现了map查找(第四章.3 节)、类型断言(第七章.10 节)或channel接收(第八章.4.2 节),每个操作都会产生一个额外的布尔结果:

v, ok = m[key] // map lookup
v, ok = x.(T) // type assertion
v, ok = <-ch // channel receive

与变量声明一样,我们可以将不需要的值赋给空白标识符:

_, err = io.Copy(dst, src) // discard byte count
_, ok = x.(T) // check type but discard result


2、可分配性

赋值语句是一种显式的赋值形式,但在程序中有许多地方会隐式地发生赋值:函数调用隐式地将参数值赋给对应的参数变量;返回语句隐式地将返回操作数赋给对应的结果变量;以及复合类型(第四章.2 节)的字面量表达式,例如这个切片:

medals := []string{"gold", "silver", "bronze"}

隐式地为每个元素赋值,就像它被写成这样:

medals[0] = "gold"
medals[1] = "silver"
medals[2] = "bronze"

虽然map和channel的元素不是普通变量,但它们也会受到类似的隐式赋值。赋值,无论是显式的还是隐式的,只有当左侧(变量)和右侧(值)具有相同类型时才是合法的。更一般地,赋值只有在值可以赋给变量的类型时才是合法的。

赋值规则对各种类型有不同的情况,因此我们会在介绍每种新类型时解释相关的情况。对于我们迄今讨论的类型,规则很简单:类型必须完全匹配,且 nil 可以赋值给任何接口类型或引用类型的变量。常量(第三章.6 节)有更灵活的赋值规则,这避免了大多数显式转换的需求。

两个值是否可以使用 ==!= 进行比较与赋值有关:在任何比较中,第一个操作数必须可以赋值给第二个操作数的类型,反之亦然。与赋值一样,我们会在介绍每种新类型时解释相关的可比较性情况。


v2ray节点购买