Appearance
整型及运算符
整型
整型是所有编程语言里最基础的数据类型,Go 语言默认支持如下这些整型类型:
数值类型 | ||||
---|---|---|---|---|
整数类型 | 字节长度 | 默认值 | 备注 | |
有符号 | int | 4 / 8 | 0 | 所占用的字节数与运行机器的 CPU 相关,在 32 位机器种,大小为 4 字节;在 64 位机器中,大小为 8 字节 |
int8 | 1 | 0 | 范围(-128 到 127) | |
int16 | 2 | 0 | 范围(-32768 到 32767) | |
int32 | 4 | 0 | 范围(-2147483648 到 2147483647) | |
int64 | 8 | 0 | 范围(-9223372036854775808 到 9223372036854775807) | |
无符号 | uint | 4 / 8 | 0 | 所占用的字节数与运行机器的 CPU 相关,在 32 位机器种,大小为 4 字节;在 64 位机器中,大小为 8 字节 |
uint8 | 1 | 0 | 范围(0 到 255) | |
uint16 | 2 | 0 | 范围(0 到 65535) | |
uint32 | 4 | 0 | 范围(0 到 4294967295) | |
uint64 | 8 | 0 | 范围(0 到 18446744073709551615) | |
byte | 1 | 0 | byte 等同于 uint8 | |
rune | 4 | 0 | rune 类型是 Unicode 字符类型,和 int32 类型等价,通常用于表示一个 Unicode 码点。rune 和 int32 可以互换使用 | |
uintptr | 4 | 0 | 可以保存任意指针的位模式的整数类型 |
Go 支持的整型类型非常丰富,你可以根据需要设置合适的整型类型,以节省内存空间,此外 int
和 int32
在 Go 语言里被认为是两种不同的类型(同理,int
和 int64
也是不同的类型),编译器也不会帮你自动做类型转换,比如以下的例子会有编译错误:
Go
var intValue1 int8
intValue2 := 8 // intValue2 将会被自动推导为 int 类型
intValue1 = intValue2 // 编译错误
编译错误类似于:
cannot use intValue2 (type int) as type int8 in assignment
使用强制类型转换可以解决这个编译错误:
Go
intValue1 = int8(intValue2)) // 编译通过
注:关于类型转换我们在后面介绍完所有数据类型后会单独介绍。
我们还可以通过 intValue := uint8(intValue2)
这种方式同时完成类型转化和赋值操作。
此外,和其他编程语言一样,可以通过增加前缀 0
来表示八进制数(如:077),增加前缀 0x
来表示十六进制数(如:0xFF),以及使用 E
来表示 10 的连乘(如:1E3 = 1000
)。
查看整数的取值范围
使用 math
包中的指定方法可以查看具体类型的取值范围
Go
fmt.Printf("int8的数值范围:%v ~ %v\n", math.MinInt8, math.MaxInt8)
fmt.Printf("int16的数值范围:%v ~ %v\n", math.MinInt16, math.MaxInt16)
fmt.Printf("in32的数值范围:%v ~ %v\n", math.MinInt32, math.MaxInt32)
fmt.Printf("int64的数值范围:%v ~ %v\n", math.MinInt64, math.MaxInt64)
/* 输出
int8的数值范围:-128 ~ 127
int16的数值范围:-32768 ~ 32767
in32的数值范围:-2147483648 ~ 2147483647
int64的数值范围:-9223372036854775808 ~ 9223372036854775807
*
关于 int
类型,Go 中的 int
类型的大小是不确定的,跟具体的平台有关系,一般来说,int
在 32 位系统中是 4 字节,在 64 位系统中是 8 字节。
字符型
byte
等同于 uint8
类型,代表了 ASCII
码的一个字符
rune
等同于 int32
类型,代表了 UTF-8
码的一个字符,当需要处理中文、日文或者其他复合字符是,需要用到 rune
类型。
对于只占用 1 字节的 ASCII
编码的字符来说,完全没有问题,例如 A、a等,用 单引号
引起来即可。
Go
var chr byte = 'A'
fmt.Println(chr)
// 输出 65
对于需要占用 2 字节以上的 Unicode
编码的字符来说,就需要用到 rune
类型了,例如 中、国,同样是使用 单引号
引起来即可。
Go
var chr rune = '中'
fmt.Println(chr)
// 输出 20013
Go 在书写 Unicode 字符时,需要在 16 进制之前加上前缀 \u
或者 \U
,因为 Unicode 至少占用 2个字节,所以使用 int16
或者 int
类型来表示。如果需要使用到 4 个字节,则使用 \u
前缀,如果需要使用到 8 个字节,则使用 \U
前缀。
Unicode 包中内置了一些用于测试字符的函数,这些函数的返回值都是一个布尔值,如下所示(其中 ch 代表需要判断的字符):
unicode.isLetter
(ch) 判断是否为字母
Go
var chr rune = 'A'
fmt.Println(unicode.IsLetter(chr))
// 输出 true
var chr rune = '2'
fmt.Println(unicode.IsLetter(chr))
// 输出 false
unicode.isDigit
(ch) 判断是否为数字
Go
var chr rune = '2'
fmt.Println(unicode.IsDigit(chr))
// 输出 true
var chr rune = 'A'
fmt.Println(unicode.IsDigit(chr))
// 输出 false
unicode.isSpace (ch)
判断是否为空白符号
Go
var chr rune = ' '
fmt.Println(unicode.IsSpace(chr))
// 输出 true
var chr rune = 'A'
fmt.Println(unicode.IsSpace(chr))
// 输出 false
注意⚠️:
- 使用自动推导声明的字符类型,默认的类型为
int32
Go
ch := 'a'
fmt.Printf("ch的类型为: %T ", ch)
// 输出 ch的类型为: int32
注意⚠️:
- int8 等同于 byte,int32 等同于 rune,在源码
builtin.go
文件中查看
Go
// byte is an alias for uint8 and is equivalent to uint8 in all ways. It is
// used, by convention, to distinguish byte values from 8-bit unsigned
// integer values.
type byte = uint8
// rune is an alias for int32 and is equivalent to int32 in all ways. It is
// used, by convention, to distinguish character values from integer values.
type rune = int32
- 使用自动推到类型初始化一个整数,默认为
int
类型
Go
num := 10
fmt.Printf("num的类型为: %T\n", num)
// 输出 num的类型为: int
运算符
算术运算符
Go 语言支持所有常规的整数四则运算:+
、-
、*
、/
和 %
(取余运算只能用于整数),不过由于强类型的关系,在 Go 语言中,不同类型的整型值不能直接进行算术运算,比如下面这样计算就会报编译错误:
Go
intValue3 := intValue1 + intValue2
编译错误信息如下:
invalid operation: intValue1 + intValue2 (mismatched types int8 and int)
类型转化之后就好了:
Go
intValue3 := intValue1 + int8(intValue2)
如果你是从动态语言转过来学习 Go,在刚开始写代码时尤其要注意这些因为类型问题产生的 bug。
在 Go 语言中,也支持自增/自减运算符,即 ++
/--
,但是只能作为语句,不能作为表达式,且只能用作后缀,不能放到变量前面:
Go
intValue1++ // 有效,intValue1 的值变成 9
intValue1 = intValue1++ // 无效,编译报错
--intValue1 // 无效,编译报错
还支持 +=
、-=
、*=
、/=
、%=
这种快捷写法:
Go
intValue1 += intValue1 // 18
intValue1 -= intValue1 // 0
intValue1 *= intValue1 // 81
intValue1 /= intValue1 // 1
intValue1 %= intValue1 // 0
比较运算符
Go 语言支持以下几种常见的比较运算符: >
、<
、==
、>=
、<=
和 !=
,比较运算符运行的结果是布尔值。
Go 是强类型语言,不同类型的值不能放在一起比较,否则会报编译错处:
GO
if intValue1 == intValue2 {
fmt.Println("intValue1 和 intValue2 相等")
}
相同类型的值才可以:
Go
if intValue1 < intValue3 {
fmt.Println("intValue1 比 intValue3 小")
}
由此可见,所有比较运算符在比较的时候都会考虑进数据类型的因素,所以不需要额外引入类似 PHP 等动态语言中的 ===
和 !==
这种严格比较运算符。
不过,各种类型的整型变量都可以直接与字面常量进行比较,比如:
Go
if intValue1 == 8 {
fmt.Println("intValue1 = 8")
}
位运算符
位运算符以二进制的方式对数值进行运算,效率更高,性能更好,Go 语言支持以下这几种位运算符:
运算符 | 含义 | 结果 |
---|---|---|
x & y | 按位与 | 把 x 和 y 都为 1 的位设为 1 |
x | y | 按位或 | 把 x 或 y 为 1 的位设为 1 |
x ^ y | 按位异或 | 把 x 和 y 一个为 1 一个为 0 的位设为 1 |
^x | 按位取反 | 把 x 中为 0 的位设为 1,为 1 的位设为 0 |
x << y | 左移 | 把 x 中的位向左移动 y 次,每次移动相当于乘以 2 |
x >> y | 右移 | 把 x 中的位向右移动 y 次,每次移动相当于除以 2 |
我们可以做一些简单的测试: |
Go
var intValueBit uint8
intValueBit = 255
intValueBit = ^intValueBit // 按位取反
fmt.Println(intValueBit) // 0
intValueBit = 1
intValueBit = intValueBit << 3 // 左移 3 位,相当于乘以 2^3 = 8
fmt.Println(intValueBit) // 8
逻辑运算符
Go 语言支持以下逻辑运算符:
运算符 | 含义 | 结果 | ||
---|---|---|---|---|
x && y | 逻辑与运算符(AND) | 如果 x 和 y 都是 true,则结果为 true,否则结果为 false | ||
x || y | 逻辑或运算符(OR) | 如果 x 或 y 是 true,则结果为 true,否则结果为 false | ||
!x | 逻辑非运算符(NOT) | 如果 x 为 true,则结果为 false,否则结果为 true | ||
逻辑运算符计算的结果也是布尔值,通常我们可以组合使用逻辑运算符和比较运算符: |
Go
if intValue1 < intValue3 && intValue1 == 8 {
fmt.Println("条件为真")
}
运算符优先级
上面介绍的 Go 语言运算符优先级如下所示(由上到下表示优先级从高到低,或者数字越大,优先级越高):
Go
6 ^(按位取反) !
5 * / % << >> & &^
4 + - | ^(按位异或)
3 == != < <= > >=
2 &&
1 ||
++
或 --
只能出现在语句中,不能用于表达式,故不参与优先级判断。