Golang中rune和byte的使用與區(qū)別
在Go語言中,rune
和byte
都是表示單個字符的類型,但它們有一些關(guān)鍵的區(qū)別。
byte 類型
byte
是 uint8
的別名,即一個 8 位無符號整數(shù),表示一個字節(jié),范圍是 0 到 255。
byte
用于表示 UTF-8 編碼中的 字節(jié),適合處理字節(jié)流和 ASCII 字符。
字符占用字節(jié)數(shù):
- ASCII 字符(0-127)占用 1 字節(jié)。
- 常見的字符,如拉丁字母、標點符號,占用 1 字節(jié)。
- 中文等非 ASCII 字符會占用 3 字節(jié)。
byte
表示:字符串 "你"
,它在 Go 中的 UTF-8 編碼是 0xE4, 0xBD, 0xA0
(十六進制)。
s := "你" for i := 0; i < len(s); i++ { fmt.Printf("byte at index %d: %d\n", i, s[i]) }
輸出:
byte at index 0: 228
byte at index 1: 189
byte at index 2: 160
rune 類型
rune
是 int32
的別名,即一個 32 位有符號整數(shù),用于表示一個 Unicode 字符。Go中所有字符(包括 ASCII 和 Unicode 字符)都是以 rune
類型表示的,范圍是 0 到 0x10FFFF。
rune
用于表示 Unicode 字符,它表示字符的 編碼點,適合處理字符操作,尤其是涉及 Unicode 字符(如中文、表情符號等)。
rune
表示:
s := "你" for _, c := range s { fmt.Printf("rune: %c, rune value: %d\n", c, c) }
輸出:
rune: 你, rune value: 20320
這表示 "你"
的 Unicode 編碼點(20320
,即 0x4F60
)被 rune
類型存儲。
UTF-8 與 Unicode 的關(guān)系
- Unicode 是字符集,而 UTF-8 是 Unicode 字符集的編碼方式之一。Unicode 定義了所有字符的編碼點,但它并沒有規(guī)定字符如何存儲和傳輸。為了實現(xiàn)跨平臺和跨語言的兼容,UTF-8 被定義為一種將 Unicode 編碼點轉(zhuǎn)換為字節(jié)序列的方式。除了 UTF-8 外,還有 UTF-16 和 UTF-32。
- 聯(lián)系:
- Unicode 為每個字符分配一個編碼點(一個數(shù)字)。
- UTF-8 通過不同長度的字節(jié)序列來編碼這些 Unicode 編碼點,使得它們可以被存儲在文件中、傳輸通過網(wǎng)絡(luò)、顯示在屏幕上等。
byte和rune的主要區(qū)別
特性 | byte | rune |
---|---|---|
類型 | uint8 (8-bit unsigned int) | int32 (32-bit signed int) |
用途 | 處理 ASCII 或字節(jié)數(shù)據(jù) | 處理 Unicode 字符 |
表示范圍 | 0 到 255 | 0 到 0x10FFFF |
常見應用 | 字節(jié)流、ASCII字符 | Unicode字符(包括多字節(jié)字符) |
存儲大小 | 1 字節(jié) | 4 字節(jié) |
字符集支持 | 僅支持 ASCII 字符 | 支持所有 Unicode 字符 |
Go的默認編碼方式
Go 字符串默認的編碼方式是 UTF-8 。所以默認使用 byte
序列來表示字符串中的每個字符。
具體來說,Go 中的字符串(string
類型)是由 UTF-8 編碼的字節(jié)序列 組成的。因此:
- 一個 Go 字符串是由多個字節(jié)(
byte
)組成的,每個字節(jié)都是 UTF-8 編碼的一個字符。 - 這些字節(jié)遵循 UTF-8 編碼,Go 字符串既可以包含 ASCII 字符(這些字符在 UTF-8 中占用 1 個字節(jié)),也可以包含多字節(jié)的 Unicode 字符(如中文字符,這些字符在 UTF-8 中通常占用 3 個字節(jié))。
s := "a" fmt.Print("占用字節(jié)數(shù):", len(s)) fmt.Printf(";類型:%T ", s[0]) fmt.Println() s1 := "你" fmt.Print("占用字節(jié)數(shù):", len(s1)) fmt.Printf(";類型:%T ", s1[0])
輸出:
占用字節(jié)數(shù):1;類型:uint8
占用字節(jié)數(shù):3;類型:uint8
遍歷方式
遍歷 byte
bytes := []byte(s)
可以直接將字符串轉(zhuǎn)為byte
,當然也可以遍歷:
- 使用
for i := 0; i < len(s); i++
,每次迭代都可以訪問字符串中的每個字節(jié)。 len(s)
返回字符串的 字節(jié)數(shù)(byte),即字符串中包含的字節(jié)總數(shù),而不是字符的數(shù)量。對于一個包含多字節(jié)字符(如中文字符)的字符串,len(s)
返回的是字符串所占用的字節(jié)數(shù)。
package main import "fmt" func main() { s := "你" // 包含中文字符 // 按字節(jié)遍歷字符串 fmt.Println("按字節(jié)遍歷字符串:") for i := 0; i < len(s); i++ { fmt.Printf("s[%d] = %v (類型: %T)\n", i, s[i], s[i]) // 輸出每個字節(jié)的值 } }
輸出:
按字節(jié)遍歷字符串:
s[0] = 228 (類型: uint8)
s[1] = 189 (類型: uint8)
s[2] = 160 (類型: uint8)
遍歷 rune
runes := []rune(s)
可以直接將字符串轉(zhuǎn)為rune
,當然也可以遍歷:
使用
for _, c := range s
遍歷字符串時,Go 會自動將字符串s
中的每個字符解碼成rune
類型,這樣即使字符是多字節(jié)的,也能正確處理。range
遍歷字符串時,按 字符(rune) 進行迭代。每次迭代返回一個 Unicode 碼點(rune) 和該字符在字符串中的索引。對于多字節(jié)字符,range
會自動跳過這些字節(jié),按字符來迭代。
package main import "fmt" func main() { s := "你" // len(s) 返回字節(jié)數(shù) fmt.Println("len(s) =", len(s)) // 輸出:3,因為“你”是由 3 個字節(jié)表示 // 使用 range 遍歷字符串,按字符(rune)遍歷 fmt.Println("使用 range 遍歷字符串,按字符(rune)遍歷:") for i, r := range s { fmt.Printf("i = %d, r = %v (類型: %T)\n", i, r, r) } }
輸出:
len(s) = 3
使用 range 遍歷字符串,按字符(rune)遍歷:
i = 0, r = 20320 (類型: int32)
補充
for i := range s
的 s[i] 其實也是byte
,但是處理中文時候會存在問題。
當你使用
for i := range s
處理英文字符串的時候,可能不會有問題,因為英文字符(ASCII 字符)在 UTF-8 編碼中是單字節(jié)表示的,所以每個字符正好對應一個字節(jié)。但是如果字符串中包含非英文字符(如中文、表情符號等),它們通常會占用多個字節(jié)。在這種情況下。使用
for i := range s
就會發(fā)現(xiàn)問題,range
會按照字符(rune
)進行遍歷,統(tǒng)計的數(shù)量是字符數(shù)(rune
)【如下只有1個】,而不是字節(jié)數(shù)(byte
)【一個中文,應該是對應3個字節(jié)】。
package main import "fmt" func main() { s := "你" // 字符串包含中文字符 // 使用 range 遍歷字符串 fmt.Println("使用 range 遍歷字符串:") for i := range s { fmt.Printf("s[%d] = %v (類型: %T)\n", i, s[i], s[i]) // 打印每個字節(jié)的值 } }
輸出:
使用 range 遍歷字符串:
s[0] = 228 (類型: uint8)
字符還原
要從 byte
序列或 rune
序列還原回原始字符串,你可以通過以下方式進行操作:
- 從
byte
序列還原字符串:可以直接使用string(byteSlice)
。 - 從
rune
序列還原字符串:可以直接使用string(runeSlice)
。
從 byte 序列還原字符串
package main import "fmt" func main() { s := "你好" // 字符串 "你好" // 將字符串轉(zhuǎn)換成 rune 切片 bytes := []byte(s) fmt.Println("bytes:", bytes) // 將 rune 切片轉(zhuǎn)換回字符串 s1 := string(bytes) fmt.Println("還原的字符串:", s1) }
bytes: [228 189 160 229 165 189]
還原的字符串: 你好
從 rune 序列還原字符串
package main import "fmt" func main() { s := "你好" // 字符串 "你好" // 將字符串轉(zhuǎn)換成 rune 切片 runes := []rune(s) fmt.Println("runes編碼:", runes) // 將 rune 切片轉(zhuǎn)換回字符串 s1 := string(runes) fmt.Println("還原的字符串:", s1) }
runes編碼: [20320 22909]
還原的字符串: 你好
到此這篇關(guān)于Golang中rune和byte的使用與區(qū)別的文章就介紹到這了,更多相關(guān)Golang rune和byte內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
go mayfly開源項目代碼結(jié)構(gòu)設(shè)計
這篇文章主要為大家介紹了go mayfly開源項目代碼結(jié)構(gòu)設(shè)計詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11