Go 語言中的 byte 類型和 rune 類型


Go 語言中定義字符串要用雙引號,而不是單引號,單引號中只能包含一個元素,表示一個字符。

Go語言中字符有兩種類型,分別是:

  1. uint8 類型,或者叫 byte 型,代表了 ASCII 碼的一個字符
  2. rune 類型,代表一個 UTF-8 字符

了解編碼知識的應該知道,ASCII 編碼字符是1個字節的,而 UTF-8 是可變長的編碼,當要表示中文等非 ASCll 編碼的字符時,需要使用 UTF-8 編碼來保證不會亂碼。關於字符編碼相關知識,推薦看這篇廖雪峰的介紹 字符編碼

假如我們要遍歷輸出一個包含中文的字符串時:

package main

import "fmt"

func main() {
	str := "hello 世界"
	for i := 0; i < len(str); i++ {
		fmt.Println(str[i])
	}
}

上述代碼的打印結果是:

104
101
108
108
111
32
228
184
150
231
149
140

Go 語言字符串存儲的其實是類型為 byte 的只讀切片,或者說一個字符串就是一堆字節。在 UTF-8 編碼中一個英文字符可以用一個字節存儲,一個中文字符需要三個或四個字節存儲,而 ASCII 碼符號只有 128 個,大於 128 的都不在范圍內。上述代碼的遍歷方式就是以 ASCII 類型來讀字符的。

可以看到輸出結果中的前 6 個都是在 ASCII 表中的,但是后 6 個就不在表中了,后面 6 個的每一個字節都不能單獨表示一個字符,而是用 3 個在一起才能表示一個字符,明顯超出了 ASCII 表的范圍,所以當打印具體字符時就會亂碼,比如我們現在來打印每一個真實字符,需要使用到占位符 %c

package main

import "fmt"

func main() {
	str := "hello 世界"
	for i := 0; i < len(str); i++ {
		fmt.Printf("%c", str[i]) // hello ä¸ç
	}
}

輸出結果為:

hello ä¸ç

明顯亂碼了。解釋這么多就是為了說明如果字符串中有非 ASCII 碼的字符時,就不能使用 byte 來表示字符,需要使用 rune 類型來表示。

使用 rune 類型來遍歷字符串

在 Go 中,有一個遍歷方式是 range,它默認就是以 UTF-8 編碼形式去讀每一個字符。當涉及到的字符串中含有非英文字符時,可以使用 range 來遍歷:

package main

import "fmt"

func main() {
	str := "hello 世界"
	for _, r := range str {
		fmt.Println(r)
	}
}

輸出結果為:

104
101
108
108
111
32
19990
30028

此時輸出的字節編碼就是 UTF-8 編碼號,UTF-8 編碼是包含 ASCII 編碼的,所以前 6 個編號還是一樣的,后面兩個編號分別代表

修改字符串

Go 語言中對字符串的修改其實不是對字符串本身的修改,而是復制字符串,同時修改值,即重新分配來內存,需要先將字符串轉化成數組,[]byte[]rune,然后再轉換成 string 型。

那么我要說的也很明顯了,就是要區別使用 []byte[]rune

對於全是ASCII編碼的字符串,使用 []byte 即可:

package main

import "fmt"

func main() {
	str := "abc"
	s2 := []byte(str)
	s2[0] = 'b'
	fmt.Println(string(s2)) //bbc
}

// string()表示強制類型轉換,轉換為字符串

對於包含中文等字符的字符串時,那就要用 []rune 了:

func main() {
    str:="白貓"
    s2:=[]rune(str)
    s2[0]='黑'
    fmt.Println(string(s2)) //黑貓
}

總結

在處理字符時,要考慮字符的編碼范圍,然后根據需要使用 byte 類型或 rune類型。

byte 類型只能正常輸出 ASCII 編碼范圍的字符;rune 類型可以輸出 UTF-8 編碼范圍的字符。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM