【Go语言系列】2.4、Go语言基本程序结构:数据类型
Go 语言是一种静态类型的编程语言。这意味着,编译器需要在编译时知晓程序里每个值的类型。数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存。
- Go语言内置以下这些基础类型:
- 布尔类型:bool
- 整型:int8、byte、int16、int、uint、uintptr等
- 浮点类型:float32、float64。
- 复数类型:complex64、complex128
- 字符串:string
- 字符类型:rune
- 错误类型:error
此外,Go语言也支持以下这些复合类型:
- 指针:pointer
- 数组:array
- 切片:slice
- 字典:map
- 通道:chan
- 结构体:struct
- 接口:interface
1、类型
1.1、布尔类型
布尔型的值只可以是常量 true 或者 false。例如:
var b bool = true
1.2、整型
序号 | 长度(字节) | 类型与描述 |
---|---|---|
1 | 1 | uint8:无符号 8 位整型 (0 到 255) |
2 | 2 | uint16:无符号 16 位整型 (0 到 65535) |
3 | 4 | uint32:无符号 32 位整型 (0 到 4294967295) |
4 | 8 | uint64:无符号 64 位整型 (0 到 18446744073709551615) |
5 | 1 | int8:有符号 8 位整型 (-128 到 127) |
6 | 2 | int16:有符号 16 位整型 (-32768 到 32767) |
7 | 4 | int32:有符号 32 位整型 (-2147483648 到 2147483647) |
8 | 8 | int64:有符号 64 位整型 (-9223372036854775808 到 9223372036854775807) |
9 | 1 | byte:类似 uint8 |
10 | 4 | rune:类似 int32 |
11 | 平台相关 | uint:无符号的整型,32 或 64 位, |
12 | 平台相关 | int:有符号的整型,32 或 64 位,在Go语言中,int与int32是不同的数据类型, 编译器不会自动做数据转换 |
13 | 同指针 | uintptr:无符号整型,用于存放一个指针,在32位平台下为4字节,64位平台下为8字节 |
例:
var value int32 value := 64 // value将会被自动推导为int类型
对整型数据可以进行数值运算、比较运算、位运算,详细在“运算符”这一节说明。
1.3、浮点型
浮点型用于表示包含小数点的数据,比如1.234就是一个浮点型数据。Go语言中的浮点类型采用IEEE-754标准的表达方式。
序号 | 长度(字节) | 类型与描述 |
---|---|---|
1 | 4 | float32:单精度 |
2 | 8 | float64:双精度 |
示例:
var fvalue1 float32 fvalue1 = 12 fvalue2 := 12.0 // 如果不加小数点,fvalue2会被推导为整型而不是浮点型
1.4、复数型
这里就是我们数学中的复数,实际上由两个实数(在计算机中用浮点数表示)构成,一个表示实部(real),一个表示虚部(imag)。
示例:
var value1 complex64 // 由2个float32构成的复数类型 value1 = 3.2 + 12i value2 := 3.2 + 12i // value2是complex128类型 value3 := complex(3.2, 12) // value3结果同 value2
对于一个复数z = complex(x, y),就可以通过Go语言内置函数real(z)获得该复数的实部,也就是x,通过imag(z)获得该复数的虚部,也就是y。更多关于复数的函数,请查阅math/cmplx标准库的文档。
1.5、字符串
在Go语言中,字符串也是一种基本类型。一个字符串是一个不可改变的字节序列,字符串可以包含任意的数据,但是通常是用来包含可读的文本。
1.5.1、字符串定义
var str string // 声明一个字符串变量 str = "Hello world" // 字符串赋值
字符串中可以使用转义字符来实现换行、缩进等效果,常用的转义字符包括:
- \n 换行符
- \r 回车符
- \t tab 键
- \u 或 \U Unicode 字符
- \\ 反斜杠自身
示例:
package main import ( "fmt" ) func main() { var str = "Hello\nworld" fmt.Println(str) }
运行结果:
Hello world
多行字符串赋值
package main import ( "fmt" ) func main() { var str = `第一行 第二行 第三行\r\n 第四行` fmt.Println(str) }
运行结果
第一行 第二行 第三行\r\n 第四行
可以看出,在这种方式下,所有的转义字符均无效,文本将会原样输出。注意 ` 不是单引号,是反引号即键盘上 1 键左边的键。多行字符串一般用于内嵌源码和内嵌数据等。
1.5.2、字符串编码
Go语言中字符串的内部实现使用 UTF-8 编码,UTF-8 是一种被广泛使用的编码格式,是文本文件的标准编码,通过 rune 类型,可以方便地对每个 UTF-8 字符进行访问。当然,Go语言也支持按照传统的 ASCII 码方式逐字符进行访问。
1.5.3、字符串操作
运算 | 含义 | 示例 |
---|---|---|
+ | 字符串连接 | "Hello" + "World" // 结果为HelloWorld |
Len() | 字符串长度 | len("HelloWorld") // 结果为10 |
[] | 取字符 | "HelloWorld" [1] // 结果为'e' |
1.5.4、字符串遍历
GO语言有两种遍历方法,一种是以字节数组的方式遍历:
package main import "fmt" func main() { str := "Hello World,你好世界" n := len(str) for i := 0; i < n; i++ { ch := str[i] // 依据下标取字符串中的字符,类型为byte fmt.Println(i, ch) } }
运行结果
0 72 1 101 2 108 3 108 4 111 5 32 6 87 7 111 8 114 9 108 10 100 11 44 12 228 13 189 14 160 15 229 16 165 17 189 18 228 19 184 20 150 21 231 22 149 23 140
在GO语言中汉字默认是UTF8编码占3个字节,字母和半角标点是ASCII编码占1个字节,所以len(str) == 24 ,输出的结果也是24行。
另一种是以Unicode字符遍历:
package main import "fmt" func main() { str := "Hello World,你好世界" for i, ch := range str { fmt.Println(i, ch) //ch的类型为rune } }
运行结果
0 72 1 101 2 108 3 108 4 111 5 32 6 87 7 111 8 114 9 108 10 100 11 44 12 20320 15 22909 18 19990 21 30028
在GO语言中Unicode字符占4个字节,故输出结果是16行。
1.5.5、字符串截取
本质上就是数组切片,这在后面的数组切片中会详细说明,这里只是举例:
package main func main() { str := "Hello World,你好世界" newStr := str[1:3] //从第1个字节开始(含),读到取到第3个字节(含) println(newStr) }
运行结果
el
需要留意的是这种字符串截取,实际是以字节的方式截取的,汉字占3个字节,可以尝试下面的代码看看结果如何
package main func main() { str := "Hello World,你好世界" newStr := str[12:15] println(newStr) }
1.5.6、字符串搜索
正向搜索首次出现的子字符串,示例:
package main import "strings" func main() { str := "Hello World,你好世界" pos := strings.Index(str, "世界") pos2 := strings.Index(str, "o") println(pos, pos2) //返回子字符串出现的位置 }
运行结果
18 4
反向搜索首次出现的子字符串,示例:
package main import "strings" func main() { str := "Hello World,你好世界" pos := strings.LastIndex(str, "好") pos2 := strings.LastIndex(str, "o") println(pos, pos2) //返回子字符串出现的位置 }
运行结果
15 7
我们可以看出在搜索子字符串时是以字节的方式遍历,汉字占3个字节
1.5.7、字符串拼接
在前面我们知道字符串拼接可以用+
来处理,简单直观,但这种方式的性能并不好,因为每次将两个字符串拼接时实际上会生成一个全新的字符串。在GO语言中也有类似于 StringBuilder(可变字符串) 的机制来进行高效的字符串连接,示例:
package main import ( "bytes" "fmt" ) func main() { firstString := "您好" secondString := "世界" // 声明字节缓冲 var stringBuilder bytes.Buffer // 把字符串写入缓冲 stringBuilder.WriteString(firstString) stringBuilder.WriteString(secondString) // 将缓冲以字符串形式输出 fmt.Println(stringBuilder.String()) }
运行输出
您好世界
1.6、字符型
字符串中的每一个元素叫做“字符”,在遍历或者单个获取字符串元素时可以获得字符。字符(Character)是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。
Go语言的字符有以下两种:
- 一种是 uint8 类型,或者叫 byte(实际上是uint8的别名) 型,代表UTF-8字符串的单个字节的值,值对应ASCII 码。
- 另一种是 rune 类型,代表一个Unicode字符,出于简化语言的考虑,Go语言的多数API都假设字符串为UTF-8编码,当需要处理中文、日文或者其他复合字符时,则需要用到 rune 类型。rune 类型等价于 int32 类型。关于rune相关的操作,可查阅Go标准库的unicode包。另外unicode/utf8包也提供了UTF8和Unicode之间的转换。尽管Unicode字符在标准库中有支持,但实际上较少使用。
在 ASCII 码表中,A 的值是 65,使用 16 进制表示则为 41,所以下面的写法是等效的:
package main func main() { //在 ASCII 码表中,A 的值是 65,使用 16 进制表示则为 41,所以下面的写法是等效的: var ch byte = 'A' //字符使用单引号括起来 var ch2 byte = 65 var ch3 byte = '\x41' //(\x 总是紧跟着长度为 2 的 16 进制数) var ch4 byte = '\101' //另外一种可能的写法是 \后面紧跟着长度为 3 的八进制数,例如 \377。 println(ch, ch2, ch3, ch4) }
在Go语言中,Unicode字符在内存中也是使用 int 来表示。在文档中,一般使用格式 U+hhhh 来表示,其中 h 表示一个 16 进制数,例如:
package main import "fmt" func main() { //在书写 Unicode 字符时,需要在 16 进制数之前加上前缀\u或者\U。因为 Unicode 至少占用 2 个字节,所以我们使用 int16 或者 int 类型来表示。如果需要使用到 4 字节,则使用\u前缀,如果需要使用到 8 个字节,则使用\U前缀。 var ch int = '\u0041' var ch2 int = '\u03B2' var ch3 int = '\U00101234' fmt.Printf("%d - %d - %d\n", ch, ch2, ch3) // integer fmt.Printf("%c - %c - %c\n", ch, ch2, ch3) // character fmt.Printf("%X - %X - %X\n", ch, ch2, ch3) // UTF-8 bytes fmt.Printf("%U - %U - %U", ch, ch2, ch3) // UTF-8 code point }
运行结果:
65 - 946 - 1053236 A - β - 41 - 3B2 - 101234 U+0041 - U+03B2 - U+101234
我们发现我们在代码中经常用fmt.Printf
来向终端输出文字,在这个示例中用到了一些格式化说明符
,它们的含义如下:
%c
:用于表示字符,当和字符配合使用时。%d
:会输出用于表示该字符的整数,%v
也是如此。%X
:表示16进制的整数%U
: 输出格式为 U+hhhh 的字符串。
Unicode 包中内置了一些用于测试字符的函数,这些函数的返回值都是一个布尔值,如下所示(其中 ch 代表字符):
package main import "unicode" func main() { // 判断是否为字母:unicode.IsLetter(ch) // 判断是否为数字:unicode.IsDigit(ch) // 判断是否为空白符号:unicode.IsSpace(ch) println(unicode.IsLetter(65)) }
输出:
true
现在我们认识了什么是Go语言中的字符,在谈字符的时候常常还会谈到字符集。那么什么是字符集呢?顾名思义,字符集(Character set)是多个字符的集合。
常见的字符集有:ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等。详细查阅:https://baike.baidu.com/item/字符集/946585?fr=aladdin
字符集为每个字符分配一个唯一的 ID,我们使用到的所有字符在 Unicode 字符集中都有一个唯一的 ID,例如上面例子中的 a 在 Unicode 与 ASCII 中的编码都是 97。
广义的 Unicode 指的是一个标准,它定义了字符集及编码规则,我们常用的UTF-8是Unicode的其中一个使用方式(编码)。 UTF是 Unicode Tranformation Format,即把Unicode转做某种格式的意思。
UTF-8便于不同的计算机之间使用网络传输不同语言和编码的文字,使得双字节的Unicode能够在现存的处理单字节的系统上正确传输。
UTF-8使用可变长度字节来储存 Unicode字符,例如ASCII字母继续使用1字节储存,重音文字、希腊字母或西里尔字母等使用2字节来储存,而常用的汉字就要使用3字节。辅助平面字符则使用4字节。
此外,还有数组(Array)
、切片(slice)
、指针(pointer)
、字典(map)
、通道(chan)
、接口(interface)
、错误(error)
、结构体(struct)
等类型,这将在后面的章节再详细说明。
感谢您的阅读,如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!
欢迎各位转载,但必须在文章页面中给出作者和原文链接!