Go語言中的字符
在Go語言中,沒有字符類型,字符類型是rune類型,rune是int32的別稱。
下面用一個簡單的程序來演示字符類型:
package main
import (
"fmt"
"reflect"
)
func main() {
r := '我'
fmt.Printf("%q的類型為:%t 二進制為:%b\n", r, r, r)
rType := reflect.TypeOf(r).Kind()
fmt.Printf("r的實際類型為:%s\n", rType)
}
程序輸出:
'我'的類型為:%!t(int32=25105) 二進制為:110001000010001
r的實際類型為:int32
Go語言天生支持Unicode,那我產生一個問題:Unicode字符的長度是多少?
這個問題的問法有沒有問題?其實仔細想想,這樣問是有問題的。首先,Unicode的基礎是一個有編號的字符集,在字符集之上又規定了模塊化的編碼等等技術層次,各種具體的編碼形式並不一致。因此,嚴格來說,Unicode是沒有“長度”這一說的,它是抽象的字符,只有Unicode的編碼才有具體的字節長度。而且不同的編碼實現,長度也不一樣。
Unicode 目前規划的總空間是17個平面(平面0至16),每個平面有 65536 個碼點。我們常用的平面0(「Basic Multilingual Plane」,即「BMP」)碼點范圍為0x0000 至 0xFFFF,這並不是 Unicode 的全部。
BMP 的字符是 Unicode 中最基礎和最常用的一部分,以 UTF-16 編碼時使用2字節,以 UTF-8編碼時使用1至3字節。超出 BMP 的字符以 UTF-16 或 UTF-8 編碼都需要4字節。另外還有一個比較少用的編碼形式,UTF-32,它編碼任何 Unicode 字符都需要4個字節。
Go語言中的字符串
Go語言的字符串有兩種方式來表示:
- 雙引號,可以使用轉義字符,如
s := "Go語言字符串\n不能跨行賦值"
- 反引號,字符串跟反引號中的格式一樣,即Raw Type
s := `Go原格式字符串
可以跨行`
Go語言的字符串是以UTF-8格式編碼並存儲的,下面有一個簡單的例子:
package main
import (
"fmt"
)
func main() {
s := "我"
fmt.Printf("s的類型為:%t, 長度為:%d, 16進制為:%x\n", s, len(s), s)
for i, b := range []byte(s) {
fmt.Printf("第%d個字節為:%b\n", i, b)
}
}
程序輸出:
s的類型為:%!t(string=我), 長度為:3, 16進制為:e68891
第0個字節為:11100110
第1個字節為:10001000
第2個字節為:10010001
變量s中存放的是這個字符串的UTF-8編碼,當你使用len(s)函數獲取字符串的長度時,獲取的是該字符串的UTF-8編碼長度,存儲一個字符可能需要 2個、3個或者4個字節,它是不固定的。
UTF-8的編碼遵循如下2條規則:
- 對於單字節的符號,字節的第一位設為0,后面7位為這個符號的unicode碼。因此對於英語字母,UTF-8編碼和ASCII碼是相同的。
- 對於n字節的符號(n>1),第一個字節的前n位都設為1,第n+1位設為0,后面字節的前兩位一律設為10。剩下的沒有提及的二進制位,全部為這個符號的unicode碼。
根據這兩條簡單的規則,我們可以把UTF-8編碼轉換為Unicode的碼點:
//utf8轉為unicode
1110 0110 1000 1000 1001 0001 // s
0110 00 1000 01 0001 // s utf8 -> unicode
0000 0000 0110 0010 0001 0001 // s utf8 -> unicode
0000 0000 0000 0000 0110 0010 0001 0001 // r
我們可以看到上面推導的結果跟程序的輸出結果相符。