Golang 入门 : 整型
整型介绍
Go语言同时提供了有符号和无符号类型的整数运算。这里有 int8
、int16
、int32
和 int64
四种截然不同大小的有符号整形数类型,分别对应 8、16、32、64 bit大小的有符号整形数,与此对应的是 uint8
、uint16
、uint32
和 uint64
四种无符号整形数类型。
数据类型 | 说明 | 取值范围 |
---|---|---|
有符号整数 | ||
int8 | 有符号 8位整数 | -128到 127 |
int16 | 有符号 16位整数 | -32768 到32767 |
int32 | 有符号 32位整数 | -2147483648到2147483647 |
int64 | 有符号 64位整数 | -9223372036854775808到9223372036854775807 |
无符号整数 | ||
uint8 | 无符号8位整数 | 0到255 |
uint16 | 无符号16位整数 | 0到65535 |
uint32 | 无符号32位整数 | 0到4294967295 |
uint64 | 无符号64位整数 | 0到18446744073709551615 |
以 u
开头的整数类型称为无符号整数类型。 无符号整数类型的值都是非负的。 一个数值类型名称中的数字表示每个这个类型的值将在内存中占有多少二进制位(以后简称位)。二进制位常称为比特(bit)。 比如,一个 uint8
的值将占有8位。 我们称 uint8
类型的值的尺寸是8位。 因此,最大的 uint8
值是 255
(2^8 - 1 ), 最大的 int8
值是 127
(2^7 - 1 ), 最小的 int8
值是 -128
(-2^7)。
以 int8
和 uint8
举例,8 代表 8个bit,能表示的数值个数有 2^8 = 256。
uint8
是无符号,能表示的都是正数,0-255,刚好256个数。
int8
是有符号,既可以正数,也可以负数,那怎么办?对半分呗,-128 ~ 127,也刚好 256个数。
int8
、int16
、int32
、int64
这几个类型的最后都有一个数值,这表明了它们能表示的数值个数是固定的。
类型别名
Go中有两种内置类型别名(type alias):
byte
是uint8
的内置别名。 我们可以将byte
和uint8
看作是同一个类型。rune
是int32
的内置别名。 我们可以将rune
和int32
看作是同一个类型。
但是 int
和 int64
不是同一种类型。
int
没有并没有指定它的位数,说明它的大小,是可以变化的
-
当你在32位的系统下,
int
和uint
都占用 4个字节,也就是32位。 -
若你在64位的系统下,
int
和uint
都占用 8个字节,也就是64位。
出于这个原因,在某些场景下,你应当避免使用 int
和 uint
,而使用更加精确的 int32
和 int64
,比如在二进制传输、读写文件的结构描述(为了保持文件的结构不会受到不同编译目标平台字节长度的影响)
这里的有符号和无符号整数 int
和 uint
,一般对应特定的CPU平台机器字大小。int
在32位系统中是4字节,在64位系统中是8字节,但是我们不能对此做任何的假设;因为不同的编译器即使在相同的硬件平台上可能产生不同的大小。
数值类型的零值都是零(但是不同类型的零在内存中占用的空间可能不同)。
关于 int
类型的取值范围,如果要把一个大的数字,放进小的数据类型则会放不进去。
var n int8
n=100
fmt.Println(n) //100 没有问题
//如果赋值为200 则不行 因为int8取值范围最大是127
var i2 uint8
i2=200
fmt.Println(i2) //200 uint8 取值范围最大是0到255
整数类型字面量
一个值的字面形式称为一个字面量,它表示此值在代码中文字体现形式(和内存中的表现形式相对应)。一个值可能会有很多种字面量形式。
整数类型值有四种字面量形式:十进制形式(decimal)、八进制形式(octal)、十六进制形式(hex)和二进制形式(binary)。 比如,下面的三个字面量均表示十进制的15:
0xF // 十六进制表示(必须使用0x或者0X开头)
0XF
017 // 八进制表示(必须使用0、0o或者0O开头)
0o17
0O17
0b1111 // 二进制表示(必须使用0b或者0B开头)
0B1111
15 // 十进制表示(必须不能用0开头)
(注意:二进制形式和以0o或0O开头的八进制形式从Go 1.13开始才支持。)
下面用一段代码分别使用二进制、八进制、十六进制来表示十进制的数值:12
package main
import (
"fmt"
)
func main() {
var num01 int = 0b1100
var num02 int = 0o14
var num03 int = 0xC
fmt.Printf("2进制数 %b 表示的是: %d \n", num01, num01)
fmt.Printf("8进制数 %o 表示的是: %d \n", num02, num02)
fmt.Printf("16进制数 %X 表示的是: %d \n", num03, num03)
}
输出
2进制数 1100 表示的是: 12
8进制数 14 表示的是: 12
16进制数 C 表示的是: 12
以上代码用过了 fmt
包的格式化功能
%b 表示为二进制
%c 该值对应的unicode码值
%d 表示为十进制
%o 表示为八进制
%q 该值对应的单引号括起来的go语法字符字面值,必要时会采用安全的转义表示
%x 表示为十六进制,使用a-f
%X 表示为十六进制,使用A-F
%U 表示为Unicode格式:U+1234,等价于"U+%04X"
rune值的字面量形式
上面已经提到,rune
类型是 int32
类型的别名。因此,rune
类型(泛指)是特殊的整数类型。一个 rune
值可以用上面已经介绍的整数类型的字面量形式表示。另一方面,很多各种整数类型的值也可以用 rune
字面量形式来表示。
在Go中,一个 rune
值表示一个 Unicode
码点。一般说来,我们可以将一个 Unicode
码点看作是一个 Unicode
字符。但是我们也应该知道,有些 Unicode
字符由多个 Unicode
码点组成。每个英文或中文 Unicode
字符值含有一个 Unicode
码点。
一个 rune
字面量由若干包在一对单引号中的字符组成。 包在单引号中的字符序列表示一个 Unicode
码点值。 rune
字面量形式有几个变种,其中最常用的一种变种是将一个 rune
值对应的 Unicode
字符直接包在一对单引号中。比如:
'a' // 一个英文字符
'π'
'众' // 一个中文字符
下面这些rune字面量形式的变种和 'a' 是等价的 (字符a的Unicode值是97)。
'\141' // 141是97的八进制表示
'\x61' // 61是97的十六进制表示
'\u0061'
'\U00000061'
注意:\
之后必须跟随三个八进制数字字符(0-7)表示一个byte值, \x
之后必须跟随两个十六进制数字字符(0-9,a-f和A-F)表示一个byte值, \u
之后必须跟随四个十六进制数字字符表示一个rune值(此rune值的高四位都为0), \U
之后必须跟随八个十六进制数字字符表示一个rune值。 这些八进制和十六进制的数字字符序列表示的整数必须是一个合法的Unicode码点值,否则编译将失败。
下面这些 println
函数调用都将打印出 true
。
package main
func main() {
println('a' == 97)
println('a' == '\141')
println('a' == '\x61')
println('a' == '\u0061')
println('a' == '\U00000061')
println(0x61 == '\x61')
println('\u4f17' == '众')
}
事实上,在日常编程中,这四种 rune
字面量形式的变种很少用来表示 rune
值。 它们多用做字符串的双引号字面量形式中的转义字符。
如果一个 rune
字面量中被单引号包起来的部分含有两个字符, 并且第一个字符是 \
,第二个字符不是 x
、 u
和 U
,那么这两个字符将被转义为一个特殊字符。 目前支持的转义组合为:
\a (rune值:0x07) 铃声字符
\b (rune值:0x08) 退格字符(backspace)
\f (rune值:0x0C) 换页符(form feed)
\n (rune值:0x0A) 换行符(line feed or newline)
\r (rune值:0x0D) 回车符(carriage return)
\t (rune值:0x09) 水平制表符(horizontal tab)
\v (rune值:0x0b) 竖直制表符(vertical tab)
\\ (rune值:0x5c) 一个反斜杠(backslash)
\' (rune值:0x27) 一个单引号(single quote)
其中,\n
在日常编程中用得最多。
一个例子:
println('\n') // 10
println('\r') // 13
println('\'') // 39
println('\n' == 10) // true
println('\n' == '\x0A') // true
rune
类型的零值常用 '\000'
、'\x00'
或 '\u0000'
等来表示。
基本数值类型字面量的适用范围
一个数值型的字面量只有在不需要舍入时,才能用来表示一个整数基本类型的值。 比如,1.0
可以表示任何基本整数类型的值,但 1.01
却不可以。 当一个数值型的字面量用来表示一个非整数基本类型的值时,舍入(或者精度丢失)是允许的。
每种数值类型有一个能够表示的数值范围。 如果一个字面量超出了一个类型能够表示的数值范围(溢出),则在编译时刻,此字面量不能用来表示此类型的值。
下表是一些例子:
字面表示 | 此字面表示可以表示哪些类型的值(在编译时刻) |
---|---|
256 | 除了int8和uint8类型外的所有的基本数值类型。 |
255 | 除了int8类型外的所有的基本数值类型。 |
-123 | 除了无符号整数类型外的所有的基本数值类型。 |
123 | 所有的基本数值类型。 |
123.000 | 所有的基本数值类型。 |
1.23e2 | 所有的基本数值类型。 |
'a' | 所有的基本数值类型。 |
1.0+0i | 所有的基本数值类型。 |
1.23 | 所有浮点数和复数基本数值类型。 |
0x10000000000000000 (16 zeros) | 所有浮点数和复数基本数值类型。 |
3.5e38 | 除了float32和complex64类型外的所有浮点数和复数基本数值类型。 |
1+2i | 所有复数基本数值类型。 |
2e+308 | 无。 |
注意几个溢出的例子:
- 字面量
0x10000000000000000
需要65个比特才能表示,所以在运行时刻,任何基本整数类型都不能精确表示此字面量。 - 在IEEE-754标准中,最大的可以精确表示的
float32
类型数值为3.40282346638528859811704183484516925440e+38
,所以3.5e38
不能表示任何float32
和complex64
类型的值。 - 在IEEE-754标准中,最大的可以精确表示的
float64
类型数值为1.797693134862315708145274237317043567981e+308
,因此2e+308
不能表示任何基本数值类型的值。 - 尽管
0x10000000000000000
可以用来表示float32
类型的值,但是它不能被任何float32
类型的值所精确表示。上面已经提到了,当使用字面量来表示非整数基本数值类型的时候,精度丢失是允许的(但溢出是不允许的)。