1、byte和rune类型
byte,占用1个字节,即8 个比特位,它和 uint8 类型本质上没有区别,它表示的是 ACSII 表中的一个字符
先定义两个 byte 类型和 uint8 类型的变量 a 和 b
func main() {
var a byte = 65
var b uint8 = 66
fmt.Printf("a 的值: %c \nb 的值: %c", a, b)
}
在 ASCII 表中,字母 A 的ASCII 的为 65 ,字母 B 的ASCII 为 66,所以上面的代码也可以写成:
func main() {
var a byte = 'A'
var b uint8 = 'B'
fmt.Printf("a 的值: %c \nb 的值: %c", a, b)
}
输出结果与上面写法一样
rune,占用4个字节,共32位比特位,它和 int32 本质上也没有区别。它表示的是一个 Unicode字符。
由于 byte 类型能表示的值是有限,只有 2^8=256 个。所以如果你想表示中文字符的话,只能使用 rune 类型。
func main() {
var a byte = 'A'
var b rune = 'B'
//var c byte = '你' //打印时会报错
var d rune = '我'
fmt.Printf("a 占用 %d 个字节数\nb 占用 %d 个字节数\n", unsafe.Sizeof(a), unsafe.Sizeof(b))
fmt.Printf("d 的值是: %c\n", d)
}
打印时的报错提示:
成功的结果:
ps:通过介绍你可能会发现发现 byte 和 uint8 没有区别,rune 和 int32 没有区别,那么问题来了,为啥golang中还要多设计 byte 和 rune 类型呢?
因为uint8 和 int32 直观上让人以为这是一个数值,而实际上也可以表示一个字符,为了消除这种错觉, byte 和 rune 两个别名类型就诞生了。
2、字符串
Go 语言里的字符串的内部实现使用UTF-8编码, 字符串的值为双引号(")中的内容。
定义一个字符串: var str string = “hello”
上面介绍的byte 和 rune 都是字符类型,若把多个字符放在一起,就组成了字符串,也就是 string 类型。比如 hello ,对照 ascii 编码表,每个字母对应的编号是:104,101,108,108,111
func main() {
var str01 string = "hello"
var str02 [5]byte = [5]byte{104, 101, 108, 108, 111}
fmt.Printf("mystr01: %s\n", str01)
fmt.Printf("mystr02: %s\n", str02)
}
可以看到输出结果一样,这说明string 的本质其实是一个 byte数组.
ps: 以上总结出字符分为 byte 和 rune,占用的大小不同。那么问题来了,hello,中国 占几个字节?
答案:Go 语言的 string 是用 uft-8 进行编码的,英文字母占一个字节,中文字母占3个字节,所以 hello,中国 的长度为 5+1+(3*2)= 12个字节。
3、字符串的修改
在Go 语言中字符串的内容是不能修改的,不能用 s[0] 这种方式修改字符串中,要修改字符串,需先将其转换成 []byte 或 []rune。要对字符串中的字节进行修改,则转换为 []byte 格式,如果要对字符串中的字符进行修改,则转换为 []rune 格式,无论哪种转换,都会重新分配内存。
举例:
func main() {
s := "Hello 世界!"
b := []byte(s) // 转换为 []byte,自动复制数据
b[5] = ',' // 修改 []byte
r := []rune(s) // 转换为 []rune,自动复制数据
r[5] = '-'
r[6] = '中'// 修改 []rune
r[7] = '国' // 修改 []rune
fmt.Printf("%s\n", s) // s 不能被修改,内容保持不变
fmt.Printf("%s\n", b) // 修改后的数据
fmt.Println(string(r))
}