使用赋值语句可以更新一个变量的值,最简单的赋值语句是将要被赋值的变量放在=的左边,新值的表达式放在=的右边。

x = 1                       // 命名变量的赋值
*p = true // 通过指针间接赋值
person.name = "bob" // 结构体字段赋值
count[x] = count[x] * scale // 数组、slice或map的元素赋值

特定的二元算术运算符和赋值语句的复合操作有一个简洁形式,例如上面最后的语句可以重写为:

count[x] *= scale

这样可以省去对变量表达式的重复计算。

数值变量也可以支持++递增和--递减语句(译注:自增和自减是语句,而不是表达式,因此x = i++之类的表达式是错误的):

v := 1
v++ // 等价方式 v = v + 1;v 变成 2
v-- // 等价方式 v = v - 1;v 变成 1

元组赋值

元组赋值是另一种形式的赋值语句,它允许同时更新多个变量的值。在赋值之前,赋值语句右边的所有表达式将会先进行求值,然后再统一更新左边对应变量的值。这对于处理有些同时出现在元组赋值语句左右两边的变量很有帮助,例如我们可以这样交换两个变量的值:

x, y = y, x

a[i], a[j] = a[j], a[i]
例子求最大公约数:
//计算两个整数的最大公约数
func gcd(x, y int) int {
for y != 0 {
x, y = y, x%y
}
return x
}

例子斐波纳契数列(Fibonacci):

//计算斐波纳契数列(Fibonacci)的第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") // function call returns two values

通常,这类函数会用额外的返回值来表达某种错误类型,例如os.Open是用额外的返回值返回一个error类型的错误,还有一些是用来返回布尔值,通常被称为ok。在稍后我们将看到的三个操作都是类似的用法。如果map查找、类型断言或通道接收出现在赋值语句的右边,它们都可能会产生两个结果,有一个额外的布尔结果表示操作是否成功:

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

注:map查找、类型断言或通道接收出现在赋值语句的右边时,并不一定是产生两个结果,也可能只产生一个结果。对于值产生一个结果的情形,map查找失败时会返回零值,类型断言失败时会发送运行时panic异常,通道接收失败时会返回零值(阻塞不算是失败)。例如下面的例子:

v = m[key]                // map查找,失败时返回零值
v = x.(T) // type断言,失败时panic异常
v = <-ch // 管道接收,失败时返回零值(阻塞不算是失败) _, ok = m[key] // map返回2个值
_, ok = mm[""], false // map返回1个值
_ = mm[""] // map返回1个值

和变量声明一样,我们可以用下划线空白标识符_来丢弃不需要的值。

_, err = io.Copy(dst, src) // 丢弃字节数
_, ok = x.(T) // 只检测类型,忽略具体值

可赋值性

赋值语句是显式的赋值形式,但是程序中还有很多地方会发生隐式的赋值行为:函数调用会隐式地将调用参数的值赋值给函数的参数变量,一个返回语句将隐式地将返回操作的值赋值给结果变量,一个复合类型的字面量也会产生赋值行为。例如下面的语句:

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

隐式地对slice的每个元素进行赋值操作,类似这样写的行为:

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

map和chan的元素,虽然不是普通的变量,但是也有类似的隐式赋值行为。

不管是隐式还是显式地赋值,在赋值语句左边的变量和右边最终的求到的值必须有相同的数据类型。更直白地说,只有右边的值对于左边的变量是可赋值的,赋值语句才是允许的。

可赋值性的规则对于不同类型有着不同要求,对每个新类型特殊的地方我们会专门解释。对于目前我们已经讨论过的类型,它的规则是简单的:类型必须完全匹配,nil可以赋值给任何指针或引用类型的变量。常量则有更灵活的赋值规则,因为这样可以避免不必要的显式的类型转换。

对于两个值是否可以用==!=进行相等比较的能力也和可赋值能力有关系:对于任何类型的值的相等比较,第二个值必须是对第一个值类型对应的变量是可赋值的,反之依然。

go语言赋值的更多相关文章

  1. spring-表达式语言-SpEL【转】

    Spring表达式语言(Spring Expression Language)简称:SpEL 课程概要: Spring表达式语言的入门介绍 Spring表达式语言的操作范围 Spring表达式语言的运 ...

  2. GO语言基础

    Go语言开发 一.Linux下搭建Go开发环境 首先下载Go语言的开发安装包,不管是在官方网站或者国内的Golang镜像都是可以的,注意区分64位和32位的安装包. 下载完安装包之后tar zxvf进 ...

  3. c语言学习笔记 - 枚举类型

    今天学习了c语言的枚举类型的使用,可能是PHP里没使用过,开始看的时候还是觉得有点怪,后来做了下例子才理解,这里做个笔记记录一下. #include <stdio.h> enum anim ...

  4. TINY语言采用递归下降分析法编写语法分析程序

    目录 自顶向下分析方法 TINY文法 消左提左.构造first follow 基本思想 python构造源码 运行结果 参考来源:聊聊编译原理(二) - 语法分析 自顶向下分析方法 自顶向下分析方法: ...

  5. js 页面刷新location.reload和location.replace的区别小结

    reload 方法,该方法强迫浏览器刷新当前页面. 语法: location.reload([bForceGet]) 参数: bForceGet, 可选参数, 默认为 false,从客户端缓存里取当前 ...

  6. 用JS获取地址栏参数的方法(超级简单)

    方法一:采用正则表达式获取地址栏参数:( 强烈推荐,既实用又方便!) function GetQueryString(name) {      var reg = new RegExp("( ...

  7. Hive 中parse_url的使用

    1.Hive的parse_url函数 parse_url(url, partToExtract[, key]) - extracts a part from a URL 解析URL字符串,partTo ...

  8. js截取url的参数(转自。。)

    用JS获取地址栏参数的方法(超级简单) 方法一:采用正则表达式获取地址栏参数:( 强烈推荐,既实用又方便!) function GetQueryString(name) {      var reg ...

  9. js常用的地址栏参数获取

    用JS获取地址栏参数的方法(超级简单) 方法一:采用正则表达式获取地址栏参数:( 强烈推荐,既实用又方便!) function GetQueryString(name) {      var reg ...

随机推荐

  1. ASP.NET MVC5+EF6+EasyUI 后台管理系统(68)-微信公众平台开发- 资源环境准备

    系列目录 前言: 本次将学习扩展企业微信公众号功能,微信公众号也是企业流量及品牌推广的主要途径,所谓工欲善其事必先利其器,调试微信必须把程序发布外网环境,导致调试速度太慢,太麻烦! 我们需要准备妥当才 ...

  2. 了不起的 nodejs-TwitterWeb 案例 bug 解决

    了不起的nodejs算是一本不错的入门书,不过书中个别案例存在bug,按照书中源码无法做出和书中相同效果,原本兴奋的心情掺杂着些许失落. 现在我们看一下第七章HTTP,一个Twitter Web客户端 ...

  3. pt-ioprofile

    pt-ioprofile是用来观察特定进程的IO信息的. 该脚本是用shell写的,有两方面的作用: pt-ioprofile does two things: ) ) is not performe ...

  4. LINQ to SQL Where条件

    1. 适用场景 实现条件的过滤和查询等功能. 2. 说明 跟SQL语句中的where作用相似,都起到了范围的限定即过滤的作用,而判断条件是紧跟后面的条件子句.where主要分为三种形式:简单形式.条件 ...

  5. 一行代码实现java list去重

    1.不带类型写法: 1 List listWithoutDup = new ArrayList(new HashSet(listWithDup)); 2.带类型写法(以String类型为例):1)Ja ...

  6. iOS开源项目周报1215

    由OpenDigg 出品的iOS开源项目周报第一期来啦.我们的iOS开源周报集合了OpenDigg一周来新收录的优质的iOS开发方面的开源项目,方便iOS开发人员便捷的找到自己需要的项目工具等. PY ...

  7. Android Studio:Failed to resolve ***

    更换电脑后,也更新了所有的SDK的tool,仍然报错:Failed to resolve  各种jar包,出现这种问题主要是因为在Android studio中默认不允许在线更新,修改方法如下:

  8. T-SQL 拆分使用指定分隔符的字符串(split string)

    比如有一个表,我们需要些一个语句像SELECT OtherID, SplitData WHERE SomeID = 'abcdef-.......' , 然后就能返回分割成单独的行. 原表: | So ...

  9. Idea下用SBT搭建Spark Helloworld

    没用过IDEA工具,听说跟Eclipse差不多,sbt在Idea其实就等于maven在Eclipse.Spark运行在JVM中,所以要在Idea下运行spark,就先要安装JDK 1.8+ 然后加入S ...

  10. Linux下的C Socket编程 -- server端的继续研究

    Linux下的C Socket编程(四) 延长server的生命周期 在前面的一个个例子中,server在处理完一个连接后便会立即结束掉自己,然而这种server并不科学啊,server应该是能够一直 ...