介绍
在上一节中,我们讨论了常用的数值类型。在本节中,你将学习 Go 语言中的字符类型。
知识点:
- ASCII 编码
- UTF-8 编码
- Unicode 字符集
byterune
在上一节中,我们讨论了常用的数值类型。在本节中,你将学习 Go 语言中的字符类型。
知识点:
byterune在计算机发展的早期,使用的是 ASCII(美国信息交换标准代码)编码格式。它使用 7 位二进制位来表示字符,总共可以表示 128(2^7)个字符。其中,从 0 到 31 位以及第 127 位表示不可显示的控制字符,而从 32 到 126 位则表示日常使用的英文大小写字母、数字和标点符号。详情请查看表格。
随着计算机的普及,支持不同语言的需求日益增长。ASCII 编码已不足以满足这一需求。因此,不同语言开发了各自的编码格式,例如简体中文的 GB2312、韩文的 EUC-KR 和俄文的 KOI8-R。
然而,由于世界上存在众多的语系,迫切需要一种能够统一所有语言的单一编码格式。Unicode(万国码)便应运而生。
1991 年,Unicode 联盟发布了 Unicode 字符集的第一个版本。其目标是将所有语言统一到一种编码格式中,使全球的计算机能够更轻松地显示和处理文本,并避免多语言环境下的兼容性问题。
然而,Unicode 最初只是一个字符集;它定义了字符的代码点,但并未规定这些代码点在计算机中如何存储。这导致它在很长一段时间内难以被广泛采用,直到互联网的兴起。
随着互联网的不断发展,作为 Unicode 实现方式之一的 UTF-8 编码逐渐流行起来。它是一种变长编码,这意味着在 UTF-8 中,不同的符号可能具有不同的字节长度。
例如,对于属于 ASCII 范围内的英文字母,它们由 1 个字节表示。字符 'y'(Unicode 值为 121)占用 1 个字节。
在日常使用中,大多数汉字占用 3 个字节。例如,字符「实」(Unicode 值为 23454)占用 3 个字节。
不过,也有一些汉字占用 4 个字节。这是因为汉字总数超过 10 万个,而 3 个字节只能表示 6 万多个字符,因此少数汉字需要 4 个字节来表示。
UTF-8 编码的另一个优势是它向后兼容 ASCII 编码。事实上,ASCII 是 UTF-8 的一个子集。UTF-8 的前 128 个字符与 ASCII 字符一一对应。这意味着原本使用 ASCII 的软件可以在几乎不作修改的情况下继续使用。由于这些优点,UTF-8 逐渐成为了首选的编码格式。
Go 语言的创始人 Rob Pike 和 Ken Thompson 也是 UTF-8 的发明者,因此 Go 与 UTF-8 有着特殊的渊源。Go 要求源代码文件必须以 UTF-8 编码保存。在操作文本字符时,UTF-8 编码是首选方案。此外,标准库还提供了许多与 UTF-8 编码和解码相关的函数。
byte 是 uint8 的别名,占用一个字节(8 位)。它可以用来表示 ASCII 表中的所有字符。然而,由于 byte 能表示的数值范围有限(256 或 2^8),在处理像汉字这样的复合字符时,我们需要使用 rune 类型。
创建一个名为 byte.go 的新文件并输入以下代码:
cd ~/project
touch byte.go
package main
import "fmt"
func main() {
var a byte = 76
fmt.Printf("Value of a: %c\n", a)
var b uint8 = 76
fmt.Printf("Value of b: %c\n", b)
var c byte = 'L'
fmt.Printf("Value of c: %c\n", c)
}
运行程序后,将输出以下结果:
go run byte.go
Value of a: L
Value of b: L
Value of c: L
占位符 %c 用于输出字符。可以看到,当数值相同时,byte 类型和 uint8 类型产生的输出是一样的。参考 ASCII 表可以发现,字母 'A' 的 ASCII 值为 65。当我们使用整数占位符 %d 输出该值时,结果也是 65。
因此,显而易见,Go 中的 byte 等同于整数类型中的 uint8。rune 也是同样的道理,但它代表了不同范围的整数值。
rune 是 int32 的别名,占用四个字节(32 位)。它用于表示复合字符,例如表情符号(emoji)。
使用以下代码更新 byte.go 文件:
package main
import "fmt"
func main() {
var a rune = '😊' // 微笑表情
fmt.Printf("Value of a: %c\n", a)
var b int32 = 9829 // Unicode 字符的十进制表示(心形符号)
fmt.Printf("Value of b: %c\n", b)
var c rune = 0x1F496 // Unicode 字符的十六进制表示(闪烁的心表情)
fmt.Printf("Value of c: %c\n", c)
var d rune = '\u0041' // 通过代码点表示的 Unicode 字符(大写字母 'A')
fmt.Printf("Value of d: %c\n", d)
var e rune = '\U0001F609' // 通过代码点表示的 Unicode 字符(眨眼表情)
fmt.Printf("Value of e: %c\n", e)
}
运行程序后,将显示以下输出:
go run byte.go
注意: 请在桌面环境或 WebIDE 的终端中运行程序,避免在 LabEx 虚拟机顶部的终端选项卡中运行。
Value of a: 😊
Value of b: ♥
Value of c: 💖
Value of d: A
Value of e: 😉
\u0041 表示大写字母 'A'。\U 格式配合代码点 0001F609 表示眨眼表情 '😉'。注意: 在 Go 中,单引号和双引号的含义不同。单引号用于表示字符,而双引号用于声明字符串。因此,在声明 byte 和 rune 类型时必须使用单引号,否则会报错。
现在,让我们巩固所学知识。创建一个名为 rune.go 的新文件并输入以下代码。补全代码,将十六进制数 0x1F648 赋值给变量 a,并使程序正确输出其值。
rune.go 应放置在 ~/project 目录下。package main
import "fmt"
func main() {
var a rune = 0x1F648
fmt.Printf("The value of a is: %c\n", a)
}
让我们回顾一下本节所学的内容:
byte 数据类型可用于表示 ASCII 字符,而 rune 数据类型可用于表示 Unicode 字符。byte 类型本质上是 uint8,而 rune 类型本质上是 int32。在本节中,我们首先解释了 ASCII、UTF-8 和 Unicode。随后,我们阐述了字符数据类型 byte、rune 与整数类型之间的关系。