和其餘語言不一樣,在 Go 語言中沒有字符類型,字符只是整數的特殊用例。html
爲何說字符只是整數的特殊用例呢?由於在 Go 中,用於表示字符的 byte
和 rune
類型都是整型的別名。在 Go 的源碼中咱們能夠看到:golang
// byte is an alias for uint8 and is equivalent to uint8 in all ways. It is
// used, by convention, to distinguish byte values from 8-bit unsigned
// integer values.
type byte = uint8
// rune is an alias for int32 and is equivalent to int32 in all ways. It is
// used, by convention, to distinguish character values from integer values.
type rune = int32
複製代碼
byte
是 uint8
的別名,長度爲 1 個字節,用於表示 ASCII 字符rune
是 int32
的別名,長度爲 4 個字節,用於表示以 UTF-8 編碼的 Unicode 碼點Tips:Unicode 從 0 開始,爲每一個符號指定一個編號,這叫作「碼點」(code point)。編程
那麼,如何在 Go 語言中表示字符呢?數組
在 Go 語言中使用單引號包圍來表示字符,例如 'j'
。函數
若是要表示 byte
類型的字符,可使用 byte
關鍵字來指明字符變量的類型:post
var byteC byte = 'j'
複製代碼
又由於 byte
實質上是整型 uint8
,因此能夠直接轉成整型值。在格式化說明符中咱們使用 %c
表示字符,%d
表示整型:ui
// 聲明 byte 類型字符
var byteC byte = 'j'
fmt.Printf("字符 %c 對應的整型爲 %d\n", byteC, byteC)
// Output: 字符 j 對應的整型爲 106
複製代碼
與 byte
相同,想要聲明 rune
類型的字符可使用 rune
關鍵字指明:編碼
var runeC rune = 'J'
複製代碼
但若是在聲明一個字符變量時沒有指明類型,Go 會默認它是 rune
類型:spa
runeC := 'J'
fmt.Printf("字符 %c 的類型爲 %T\n", runeC, runeC)
// Output: 字符 J 的類型爲 int32
複製代碼
看到這裏你可能會問了,既然都用於表示字符,爲何還須要兩種類型呢?code
咱們知道,byte
佔用一個字節,所以它能夠用於表示 ASCII 字符。而 UTF-8 是一種變長的編碼方法,字符長度從 1 個字節到 4 個字節不等。byte
顯然不擅長這樣的表示,就算你想要使用多個 byte
進行表示,你也無從知曉你要處理的 UTF-8 字符究竟佔了幾個字節。
所以,若是你在中文字符串上狂妄地進行截取,必定會輸出亂碼:
testString := "你好,世界"
fmt.Println(testString[:2]) // 輸出亂碼,由於截取了前兩個字節
fmt.Println(testString[:3]) // 輸出「你」,一箇中文字符由三個字節表示
複製代碼
此時就須要 rune
的幫助了。利用 []rune()
將字符串轉爲 Unicode 碼點再進行截取,這樣就無需考慮字符串中含有 UTF-8 字符的狀況了:
testString := "你好,世界"
fmt.Println(string([]rune(testString)[:2])) // 輸出:「你好」
複製代碼
Tips:Unicode 和 ASCII 同樣,是一種字符集,UTF-8 則是一種編碼方式。
字符串遍歷有兩種方式,一種是下標遍歷,一種是使用 range
。
因爲在 Go 語言中,字符串以 UTF-8 編碼方式存儲,使用 len()
函數獲取字符串長度時,獲取到的是該 UTF-8 編碼字符串的字節長度,經過下標索引字符串將會產生一個字節。所以,若是字符串中含有 UTF-8 編碼字符,就會出現亂碼:
testString := "Hello,世界"
for i := 0; i < len(testString); i++ {
c := testString[i]
fmt.Printf("%c 的類型是 %s\n", c, reflect.TypeOf(c))
}
/* Output: H 的類型是 uint8(ASCII 字符返回正常) e 的類型是 uint8 l 的類型是 uint8 l 的類型是 uint8 o 的類型是 uint8 ï 的類型是 uint8(從這裏開始出現了奇怪的亂碼) ¼ 的類型是 uint8 的類型是 uint8 ä 的類型是 uint8 ¸ 的類型是 uint8 的類型是 uint8 ç 的類型是 uint8 的類型是 uint8 的類型是 uint8 */
複製代碼
range
遍歷則會獲得 rune
類型的字符:
testString := "Hello,世界"
for _, c := range testString {
fmt.Printf("%c 的類型是 %s\n", c, reflect.TypeOf(c))
}
/* Output: H 的類型是 int32 e 的類型是 int32 l 的類型是 int32 l 的類型是 int32 o 的類型是 int32 , 的類型是 int32 世 的類型是 int32 界 的類型是 int32 */
複製代碼
byte
是 uint8
的別名,長度爲 1 個字節,用於表示 ASCII 字符rune
則是 int32
的別名,長度爲 4 個字節,用於表示以 UTF-8 編碼的 Unicode 碼點rune
類型的字符則使用 range
方法進行遍歷若是你以爲文章寫得不錯,請幫我兩個小忙:
你的鼓勵是我創做最大的動力,感謝你們!