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 |
| 常見應(yīng)用 | 字節(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é)表示的,所以每個字符正好對應(yīng)一個字節(jié)。但是如果字符串中包含非英文字符(如中文、表情符號等),它們通常會占用多個字節(jié)。在這種情況下。使用
for i := range s就會發(fā)現(xiàn)問題,range會按照字符(rune)進行遍歷,統(tǒng)計的數(shù)量是字符數(shù)(rune)【如下只有1個】,而不是字節(jié)數(shù)(byte)【一個中文,應(yīng)該是對應(yīng)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
簡單聊聊Golang中defer預(yù)計算參數(shù)
在golang當中defer代碼塊會在函數(shù)調(diào)用鏈表中增加一個函數(shù)調(diào)用,下面這篇文章主要給大家介紹了關(guān)于Golang中defer預(yù)計算參數(shù)的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-03-03

