收录于 《Go 基础系列》,作者:潇洒哥老苗。
学到什么
- 什么是常量?
- 如何定义常量?
- 常量和变量有什么不同?
- 如何使用常量?
- 有哪些运算符?
- 如何使用运算符?
- 运算符的优先级?
常量
1. 概念
常量的值在程序运行期间是不能改变的,而变量的值在运行期间是可以改变的。
举个实际使用到常量的几个场景:
- web开发时,根据业务定义的错误码
- 程序的发行版本号
- 数据库连接池数量(如果不通过配置文件时)
- 等等
在使用时,只要你确定在程序运行期间不改变它的值,就可以使用常量。
2. 定义
常量的定义格式: const 常量名 [常量类型] = 常量值
[常量类型]
可以省略,编译器会根据值来推导类型。
// 显示定义 | |
const b string = "abc" | |
// 隐式定义 | |
const b = "abc" |
对于常量值的数据类型,只可以定义为布尔型、数字型(整数型、浮点型和复数)和字符串型。
// 默认 bool | |
const isOpen = true | |
// 默认 rune,int32 的别名 | |
const MyRune = 'r' | |
// 默认 int | |
const occupancyLimit = 12 | |
// 默认 float64 | |
const vatRate = 29.87 | |
// 默认 complex128 | |
const complexNumber = 1 + 2i | |
// 默认 string | |
const hotelName = "Gopher Hotel" |
定义时还有两种写法。
// 第一种,常量块的形式 | |
const ( | |
isOpen = true | |
MyRune = 'r' | |
) | |
// 第二种,并行赋值 | |
const limit, rate = 12, 29.8 |
注:第一种“常量块”的形式是实际中用的比较多的。
3. 隐式定义不限制
是什么意思呢?意思就是我在定义时,省略了数据类型后,值的大小是不受限制,即不会产生溢出。
const num = 111111111111111111111111111111111111111111111
如果显示定义数字型常量,它必然会有存储空间大小限制。比如:定义一个int64 类型,它的最大值为 9223372036854775807,但如果超过这个最大值,就会溢出,程序自然会抛异常,还原如下:
// 文件名 main.go | |
package main | |
import "fmt" | |
func main() { | |
// 最大值 + 1 | |
const num int64 = 9223372036854775808 | |
} |
运行后输出以下结果:
go run main.go | |
## 输出 | |
.\main.go:6:8: constant 9223372036854775808 overflows int64 |
4. iota 用法
iota
是 Go 语言中的一个关键字,先看代码,再解释。
const ( | |
a = iota // a = 0 | |
b // b = 1 | |
c // c = 2 | |
d = 5 // d = 5 | |
e // e = 5 | |
) |
iota
从0开始,每增加新的一行就会自动加一,直到重新声明一个 const
时 iota
重置为0,遇到新的赋值时 iota
将不再应用。
再说说一个 const块
中出现多个 iota
关键字时是什么情况。
const ( | |
a = iota // a = 0 | |
b // b = 1 | |
c // c = 2 | |
d = 5 // d = 5 | |
e = iota // e = 4 | |
) |
当 d
常量赋值为 5 时,iota
只是暂时不应用,直到再次使用,而 iota
继续保持在增加新的一行时自增一。
iota
也可以参加运算,举几个例子就明白了。
// 从1开始自动加一 | |
const ( | |
Apple = iota + 1 // Apple=1 | |
Cherimoya // Cherimoya=2 | |
Elderberry // Elderberry=3 | |
) | |
// 并行赋值两个常量,iota 只会在第一行增长一次 | |
// 而不会因为使用了两次就增长两次 | |
const ( | |
Apple, Banana = iota + 1, iota + 2 // Apple=1 Banana=2 | |
Cherimoya, Durian // Cherimoya=2 Durian=3 | |
Elderberry, Fig // Elderberry=3, Fig=4 | |
) | |
// iota参与位运算 | |
const ( | |
Open = 1 << iota // 0001 | |
Close // 0010 | |
Pending // 0100 | |
) |
运算符
1. 分类
- 算术运算符:+(加),-(减),*(乘),/(除),%(求余),++(自增),–(自减)
- 比较运算符:==(等于),!=(不等于),>(大于),<(小于), >=(大于等于), <=(小于等于)
- 赋值运算符:=(右值赋值给左侧), += , -=, *=, /=,%=, &=, |=, ^=, >>=, <<= (前面的都是左侧值和右侧值运算后再赋值给左侧)
- 位运算符: ****&(按位与),|(按位或),^(按位异或/取反),>>(右移位),<<(左移位)
- 逻辑运算符:&&(与),||(或),!(非)
- 其他运算符:&(取变量地址),*(指针)
2. 算数运算符
初始化 a 和 b 两个变量进行运算,使用如下:
a := 10 | |
b := 3 | |
fmt.Println("a+b=", a+b) // a+b= 13 | |
fmt.Println("a-b=", a-b) // a-b= 7 | |
fmt.Println("a*b=", a*b) // a*b= 30 | |
fmt.Println("a/b=", a/b) // a/b= 3 | |
// 不支持 ++a | |
a++ | |
fmt.Println("a++=", a) // a++= 11 | |
// 错误写法:fmt.Println(a++), | |
// 必须经过运算后才可使用, 自减也是一样 | |
// 不支持 --a | |
a-- | |
fmt.Println("a--=", a) // a--= 10 |
注:自增和自减去只支持后置的++或–。
3. 比较运算符
初始化 a 和 b 两个变量,进行比较,使用如下:
a := 10 | |
b := 3 | |
fmt.Println("a==b:", a == b) // a==b: false | |
fmt.Println("a!=b:", a != b) // a!=b: true | |
fmt.Println("a>b:", a > b) // a>b: true | |
fmt.Println("a>=b:", a >= b) // a>=b: true | |
fmt.Println("a<b:", a < b) // a<b: false | |
fmt.Println("a<=b:", a <= b) // a<=b: false |
4. 赋值运算符
初始化 a 变量 为10,使用如下:
// 将 10 赋值给 a 变量 | |
var a = 10 // 简写方式: a := 10 | |
// 在10的基础上加2 | |
// 等价于 a = a + 2 | |
a += 2 // 12 | |
// 在12的基础上减3 | |
// 等价于 a = a - 3 | |
a -= 3 // 9 | |
// 在9的基础上乘以2 | |
// 等价于 a = a * 2 | |
a *= 2 // 18 | |
// 在18的基础上除以3 | |
// 等价于 a = a / 3 | |
a /= 3 // 6 | |
// 在6的基础上对4求余 | |
// 等价于 a = a % 4 | |
a %= 4 // 2 |
注:&=、|=、^=、>>=、<<= 运算符就省略不写了(不是懒,感觉太啰嗦了),看懂下面的位运算符的意思,照上面的类比理解就明白了。
5. 位运算符
初始化 a 和 b 两个变量进行运算,前提要明白十进制如何转化为二进制,使用如下:
a := 4 // 二进制: 0100 | |
b := 3 // 二进制: 0011 | |
// 按位与 | |
// 对应位都为1时,结果为1 | |
a & b // 0 | |
// 按位或 | |
// 对应位有一个为1时,结果为1 | |
a | b // 7 | |
// 按位异或 | |
// 对应位相同时为0,不相同时为1 | |
a ^ b // 7 | |
// 按位取反 | |
// 取反后变成1100, 最高位1代表负数 | |
^b // -4 | |
// 按位右移 | |
// 将二进制 0100 向右移动一位变成 0010 | |
a >> 1 // 2 | |
// 按位左移 | |
// 将二进制 0100 向左移动一位变成 1000 | |
a << 1 // 8 |
注:”按位异或“和”按位取反“的运算符是一样的,区别在于操作数数量上,”按位异或“操作数为两个,”按位取反“操作数是一个。
6. 逻辑运算符
逻辑运算符只能应用到 bool 类型上,初始化 a 和 b 两个 bool 值,使用如下:
a := true | |
b := false | |
// 与运算,都为 true 时,结果为 true | |
a && b // false | |
// 或运算,有一个为 true 时,结果为 true | |
a || b // true | |
// 非运算,为 true 时,结果为 false | |
// 反之,为 false 时,结果为true | |
!a // false | |
!b // true |
7. 其他运算符
就剩下两个运算符的使用了,往下看:
// 变量地址 | |
a := 1 | |
fmt.Println(&a) // 0xc00000a9b0 | |
// 指针变量,在变量地址前加个 * 代表取出值 | |
p := &a | |
fmt.Println(*p) // 1 |
8. 运算符优先级
优先级:表中”优先级“列数字越大优先级越高,规定了不同优先级的结合顺序,举例如下:
// '*' 优先级 > '+' 优先级 | |
// 等价于 a := (2 * 3) + 1 | |
a := 2 * 3 + 1 |
结合性:表中“结合性”列中的“从左到右”和“从右到左”表示同优先级运算符的结合顺序,举例如下
// 从表中看到结合性是从左到右 | |
// 等价于 a := (1 + 2) + 3 | |
a := 1 + 2 +3 |
总结
本篇讲解了“常量”和“运算符”的使用,如果掌握了其它编程语言,那重点看看常量怎么使用就行,尤其是 iota
关键字的使用,至于“运算符”语言之间都差不多,就可以偷懒不看了,有啥不懂的就在下方留言。