Golang中rune和byte的使用與區(qū)別
在Go語(yǔ)言中,rune
和byte
都是表示單個(gè)字符的類(lèi)型,但它們有一些關(guān)鍵的區(qū)別。
byte 類(lèi)型
byte
是 uint8
的別名,即一個(gè) 8 位無(wú)符號(hào)整數(shù),表示一個(gè)字節(jié),范圍是 0 到 255。
byte
用于表示 UTF-8 編碼中的 字節(jié),適合處理字節(jié)流和 ASCII 字符。
字符占用字節(jié)數(shù):
- ASCII 字符(0-127)占用 1 字節(jié)。
- 常見(jiàn)的字符,如拉丁字母、標(biāo)點(diǎn)符號(hào),占用 1 字節(jié)。
- 中文等非 ASCII 字符會(huì)占用 3 字節(jié)。
byte
表示:字符串 "你"
,它在 Go 中的 UTF-8 編碼是 0xE4, 0xBD, 0xA0
(十六進(jìn)制)。
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 類(lèi)型
rune
是 int32
的別名,即一個(gè) 32 位有符號(hào)整數(shù),用于表示一個(gè) Unicode 字符。Go中所有字符(包括 ASCII 和 Unicode 字符)都是以 rune
類(lèi)型表示的,范圍是 0 到 0x10FFFF。
rune
用于表示 Unicode 字符,它表示字符的 編碼點(diǎn),適合處理字符操作,尤其是涉及 Unicode 字符(如中文、表情符號(hào)等)。
rune
表示:
s := "你" for _, c := range s { fmt.Printf("rune: %c, rune value: %d\n", c, c) }
輸出:
rune: 你, rune value: 20320
這表示 "你"
的 Unicode 編碼點(diǎn)(20320
,即 0x4F60
)被 rune
類(lèi)型存儲(chǔ)。
UTF-8 與 Unicode 的關(guān)系
- Unicode 是字符集,而 UTF-8 是 Unicode 字符集的編碼方式之一。Unicode 定義了所有字符的編碼點(diǎn),但它并沒(méi)有規(guī)定字符如何存儲(chǔ)和傳輸。為了實(shí)現(xiàn)跨平臺(tái)和跨語(yǔ)言的兼容,UTF-8 被定義為一種將 Unicode 編碼點(diǎn)轉(zhuǎn)換為字節(jié)序列的方式。除了 UTF-8 外,還有 UTF-16 和 UTF-32。
- 聯(lián)系:
- Unicode 為每個(gè)字符分配一個(gè)編碼點(diǎn)(一個(gè)數(shù)字)。
- UTF-8 通過(guò)不同長(zhǎng)度的字節(jié)序列來(lái)編碼這些 Unicode 編碼點(diǎn),使得它們可以被存儲(chǔ)在文件中、傳輸通過(guò)網(wǎng)絡(luò)、顯示在屏幕上等。
byte和rune的主要區(qū)別
特性 | byte | rune |
---|---|---|
類(lèi)型 | uint8 (8-bit unsigned int) | int32 (32-bit signed int) |
用途 | 處理 ASCII 或字節(jié)數(shù)據(jù) | 處理 Unicode 字符 |
表示范圍 | 0 到 255 | 0 到 0x10FFFF |
常見(jiàn)應(yīng)用 | 字節(jié)流、ASCII字符 | Unicode字符(包括多字節(jié)字符) |
存儲(chǔ)大小 | 1 字節(jié) | 4 字節(jié) |
字符集支持 | 僅支持 ASCII 字符 | 支持所有 Unicode 字符 |
Go的默認(rèn)編碼方式
Go 字符串默認(rèn)的編碼方式是 UTF-8 。所以默認(rèn)使用 byte
序列來(lái)表示字符串中的每個(gè)字符。
具體來(lái)說(shuō),Go 中的字符串(string
類(lèi)型)是由 UTF-8 編碼的字節(jié)序列 組成的。因此:
- 一個(gè) Go 字符串是由多個(gè)字節(jié)(
byte
)組成的,每個(gè)字節(jié)都是 UTF-8 編碼的一個(gè)字符。 - 這些字節(jié)遵循 UTF-8 編碼,Go 字符串既可以包含 ASCII 字符(這些字符在 UTF-8 中占用 1 個(gè)字節(jié)),也可以包含多字節(jié)的 Unicode 字符(如中文字符,這些字符在 UTF-8 中通常占用 3 個(gè)字節(jié))。
s := "a" fmt.Print("占用字節(jié)數(shù):", len(s)) fmt.Printf(";類(lèi)型:%T ", s[0]) fmt.Println() s1 := "你" fmt.Print("占用字節(jié)數(shù):", len(s1)) fmt.Printf(";類(lèi)型:%T ", s1[0])
輸出:
占用字節(jié)數(shù):1;類(lèi)型:uint8
占用字節(jié)數(shù):3;類(lèi)型:uint8
遍歷方式
遍歷 byte
bytes := []byte(s)
可以直接將字符串轉(zhuǎn)為byte
,當(dāng)然也可以遍歷:
- 使用
for i := 0; i < len(s); i++
,每次迭代都可以訪(fǎng)問(wèn)字符串中的每個(gè)字節(jié)。 len(s)
返回字符串的 字節(jié)數(shù)(byte),即字符串中包含的字節(jié)總數(shù),而不是字符的數(shù)量。對(duì)于一個(gè)包含多字節(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 (類(lèi)型: %T)\n", i, s[i], s[i]) // 輸出每個(gè)字節(jié)的值 } }
輸出:
按字節(jié)遍歷字符串:
s[0] = 228 (類(lèi)型: uint8)
s[1] = 189 (類(lèi)型: uint8)
s[2] = 160 (類(lèi)型: uint8)
遍歷 rune
runes := []rune(s)
可以直接將字符串轉(zhuǎn)為rune
,當(dāng)然也可以遍歷:
使用
for _, c := range s
遍歷字符串時(shí),Go 會(huì)自動(dòng)將字符串s
中的每個(gè)字符解碼成rune
類(lèi)型,這樣即使字符是多字節(jié)的,也能正確處理。range
遍歷字符串時(shí),按 字符(rune) 進(jìn)行迭代。每次迭代返回一個(gè) Unicode 碼點(diǎn)(rune) 和該字符在字符串中的索引。對(duì)于多字節(jié)字符,range
會(huì)自動(dòng)跳過(guò)這些字節(jié),按字符來(lái)迭代。
package main import "fmt" func main() { s := "你" // len(s) 返回字節(jié)數(shù) fmt.Println("len(s) =", len(s)) // 輸出:3,因?yàn)椤澳恪笔怯?3 個(gè)字節(jié)表示 // 使用 range 遍歷字符串,按字符(rune)遍歷 fmt.Println("使用 range 遍歷字符串,按字符(rune)遍歷:") for i, r := range s { fmt.Printf("i = %d, r = %v (類(lèi)型: %T)\n", i, r, r) } }
輸出:
len(s) = 3
使用 range 遍歷字符串,按字符(rune)遍歷:
i = 0, r = 20320 (類(lèi)型: int32)
補(bǔ)充
for i := range s
的 s[i] 其實(shí)也是byte
,但是處理中文時(shí)候會(huì)存在問(wèn)題。
當(dāng)你使用
for i := range s
處理英文字符串的時(shí)候,可能不會(huì)有問(wèn)題,因?yàn)橛⑽淖址ˋSCII 字符)在 UTF-8 編碼中是單字節(jié)表示的,所以每個(gè)字符正好對(duì)應(yīng)一個(gè)字節(jié)。但是如果字符串中包含非英文字符(如中文、表情符號(hào)等),它們通常會(huì)占用多個(gè)字節(jié)。在這種情況下。使用
for i := range s
就會(huì)發(fā)現(xiàn)問(wèn)題,range
會(huì)按照字符(rune
)進(jìn)行遍歷,統(tǒng)計(jì)的數(shù)量是字符數(shù)(rune
)【如下只有1個(gè)】,而不是字節(jié)數(shù)(byte
)【一個(gè)中文,應(yīng)該是對(duì)應(yīng)3個(gè)字節(jié)】。
package main import "fmt" func main() { s := "你" // 字符串包含中文字符 // 使用 range 遍歷字符串 fmt.Println("使用 range 遍歷字符串:") for i := range s { fmt.Printf("s[%d] = %v (類(lèi)型: %T)\n", i, s[i], s[i]) // 打印每個(gè)字節(jié)的值 } }
輸出:
使用 range 遍歷字符串:
s[0] = 228 (類(lèi)型: uint8)
字符還原
要從 byte
序列或 rune
序列還原回原始字符串,你可以通過(guò)以下方式進(jìn)行操作:
- 從
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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
go mayfly開(kāi)源項(xiàng)目代碼結(jié)構(gòu)設(shè)計(jì)
這篇文章主要為大家介紹了go mayfly開(kāi)源項(xiàng)目代碼結(jié)構(gòu)設(shè)計(jì)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11Go+Redis實(shí)現(xiàn)常見(jiàn)限流算法的示例代碼
限流是項(xiàng)目中經(jīng)常需要使用到的一種工具,一般用于限制用戶(hù)的請(qǐng)求的頻率,也可以避免瞬間流量過(guò)大導(dǎo)致系統(tǒng)崩潰,或者穩(wěn)定消息處理速率。這篇文章主要是使用Go+Redis實(shí)現(xiàn)常見(jiàn)的限流算法,需要的可以參考一下2023-04-04golang中的單引號(hào)轉(zhuǎn)義問(wèn)題
這篇文章主要介紹了golang中的單引號(hào)轉(zhuǎn)義問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02Go語(yǔ)言中的錯(cuò)誤處理最佳實(shí)踐詳解
這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言中的錯(cuò)誤處理的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),對(duì)我們深入了解Go語(yǔ)言有一定的幫助,需要的可以參考下2023-08-08利用Golang生成整數(shù)隨機(jī)數(shù)方法示例
這篇文章主要介紹了利用Golang生成整數(shù)隨機(jī)數(shù)的相關(guān)資料,文中給出了詳細(xì)的介紹和完整的示例代碼,相信對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-04-04簡(jiǎn)單聊聊Golang中defer預(yù)計(jì)算參數(shù)
在golang當(dāng)中defer代碼塊會(huì)在函數(shù)調(diào)用鏈表中增加一個(gè)函數(shù)調(diào)用,下面這篇文章主要給大家介紹了關(guān)于Golang中defer預(yù)計(jì)算參數(shù)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-03-03Golang處理parquet文件實(shí)戰(zhàn)指南
這篇文章主要給大家介紹了關(guān)于Golang處理parquet文件的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Golang具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-03-03