Go 學習筆記 - String 底層實現原理
1、字符集
-
計算機裏 1bit 可以是 0 也可以是 1
-
8bit 組成 1byte, 全爲 0 時表示數字 0, 全爲 1 時表示數字 255
-
2byte 可以表示 65536 個數字, 更多字節數可以表示更大的數字範圍
-
字符如何表示呢?
-
ASCII 字符集: 一共收錄了 128 個字符, 其擴展字符集也只有 256 個 (包括英文字母、阿拉伯數字、西文字、控制字符)
-
GB2312: 包括了簡體中文、拉丁字母、日文假名等等
-
BIG5: 包括了繁體字等
- unicode: 於 1990 年開始研發, 1994 年正式公佈, 全球統一化字符編碼
2、如何表示混合字符
-
比如 "abc 字母歌" 這種字符如何存儲呢?
-
如果直接用 unicode 字符集表示, 如下圖
func main() {
//string轉化爲unicode編碼切片
str := "hello,world世界"
unicode := []rune(str)
//打印unicode編碼
fmt.Println(unicode)
for _, v := range unicode {
//打印二進制
fmt.Printf("%b\n", v)
}
}
-
問題來了
-
這麼多二進制編碼有長有短, 你怎麼知道哪個是哪個呢?
-
所以就會有字符邊界劃分的問題?
-
定長編碼可以解決這個問題, 但是確實有點浪費空間
-
UTF-8 編碼: 它它是一種變長編碼, 能有效地解決上述問題, 可以根據字符大小範圍指定字符邊界
-
0-127 之間的, 佔用 1 字節, 以 0 標識在字節開頭
-
128-2047 之間的, 佔用 2 字節, 以 110 和 10 標識在字節開頭
-
2048-65535 之間的, 佔用 3 字節, 分別以 1110、10、10 標識在字節開頭
-
以此類推, 更多字節的開頭都遵循這樣的規則
3、Go 語言 string
- Go 語言默認採用 UTF-8 編碼
func main() {
//string轉化爲unicode編碼切片
str := "hello,world世界"
//打印str的utf-8二進制編碼
strSlice := []byte(str)
for _, v := range strSlice {
fmt.Printf("%b\n", v)
}
}
/*
1101000 - h
1100101 - e
1101100 - l
1101100 - l
1101111 - o
101100 - ,
1110111 - w
1101111 - o
1110010 - r
1101100 - l
1100100 - d
11100100 10111000 10010110 - 世
11100111 10010101 10001100 - 界
*/
-
Go 語言中上述的 str 變量是什麼樣的結構呢?
-
對於 string 變量, Go 語言認爲它不可被修改, 所以 string 變量會記錄執行只讀字符串的內存起始地址
-
如何找到字符內存地址的結尾地址呢? 在 C 語言中, 會在字符的結尾帶上 \0, 但這樣就不能寫入 \ 0 本身這種字符了
-
爲了要找到結尾標識, go 語言會在變量後面標識只讀字符的字節數
- string 底層數據結構
type stringStruct struct {
str unsafe.Pointer // 底層數組指針
len int // 字符串長度,可以通過 len(string) 返回
}
-
如何修改字符串內容呢?
-
slice 底層數據結構
type slice struct {
array unsafe.Pointer // 底層數組指針,真正存放數據的地方
len int // 切片長度,通過 len(slice) 返回
cap int // 切片容量,通過 cap(slice) 返回
}
-
可以把字符串變量的值賦值給 []byte 這樣的切片, 會給變量從新分配內存, 並且會拷貝字符對應的 utf-8 編碼到切片中
-
如何使用實現 []byte 和字符串之間的零拷貝轉換?
func StringToBytes(str string) []byte {
var b []byte
// 切片的底層數組、len字段,指向字符串的底層數組,len字段
*(*string)(unsafe.Pointer(&b)) = str
// 切片的 cap 字段賦值爲 len(str)的長度,切片的指針、len 字段各佔八個字節,直接偏移16個字節
*(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&b)) + 2*uintptr(8))) = len(str)
return b
}
func BytesToString(data []byte) string {
// 直接轉換
return *(*string)(unsafe.Pointer(&data))
}
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/Okv0uuJJl4yOy1GxWLScHw