計算機是二進制的,字符最終也是轉換成二進制保存起來的。字符集就是定義字符對應的數值。 Unicode是一個字符集,爲每一個字符規定一個用來表示該字符的數字,可是並無規定該數字的二進制保存方式,utf8規定了對於unicode值的二進制保存方式。bash
utf8是可變長度字符編碼,不一樣的字符會對應不一樣大小的存儲方式,好比"a"字符(unicode值97)用1個字節,而"中"字符(unicode值20013)則用3個字節。字符的unicode值決定了字符須要用多少字節表示函數
Go語言中,string就是隻讀的採用utf8編碼的字節切片(slice) 所以用len函數獲取到的長度並非字符個數,而是字節個數。 for循環遍歷輸出的也是各個字節。工具
a := "Randal";
for i := 0; i < len(a); i++ {
fmt.Printf("%x ", a[i])
fmt.Printf("%c ", a[i])
}
// 輸出結果
52 61 6e 64 61 6c
Randal
複製代碼
a := "中國";
fmt.Println(len(a))
for i := 0; i < len(a); i++ {
fmt.Printf("%x ", a[i])
}
for i := 0; i < len(a); i++ {
fmt.Printf("%c ", a[i])
}
// 輸出結果
6
E4 B8 AD E5 9B BD
ä¸å½
複製代碼
fmt.Printf函數支持從一個表達式列表生成格式化的輸出,它的第一個參數是格式化指示字符串,由它指定其餘參數如何格式化。其中%c,用於輸出字符(Unicode碼點),碼點是字符的unicode值。 因爲go採用的是utf8編碼,而「中」的utf8編碼是E4 B8 AD(所表示的unicode值是U+4E2D), https://unicode-table.com/en/00E4/ 經過這個連接能夠看到ä的unicode編碼就是U+00E4。編碼
從上面的例子中能夠看出當字符的utf8編碼超過1個字節的時候格式化輸出單個字符就會出現亂碼的狀況,若是但願解決亂碼問題就要用到rune了spa
rune是int32的別名,表明字符的Unicode編碼,採用4個字節存儲,將string轉成rune就意味着任何一個字符都用4個字節來存儲其unicode值,這樣每次遍歷的時候返回的就是unicode值,而再也不是字節了,這樣就能夠解決亂碼問題了code
var s string
s = "中國"
r := []rune(s)
for i := 0; i < len(r); i++ {
fmt.Printf("%x", r[i])
}
for i := 0; i < len(r); i++ {
fmt.Printf("%c", r[i])
}
// 輸出結果
4e2d 56fd
中國
複製代碼
經過for range對字符串進行遍歷時,每次獲取到的對象都是rune類型的,所以下面的方式也能夠解決亂碼問題cdn
var s string
s = "中國"
for _, item := range s {
fmt.Printf("%c", item)
}
// 輸出結果
中國
複製代碼
bytes操做的對象也是字節切片,與string的不可變不一樣,byte是可變的,所以string按增量方式構建字符串會致使屢次內存分配和複製,使用bytes就不會於是更高效一點對象
package main
import (
"fmt"
"bytes"
)
func main() {
var s string
s = "中國"
var b bytes.Buffer
b.WriteString("中國")
for i := 0; i < 10; i++ {
s += "a"
b.WriteString("a")
}
fmt.Println(s)
fmt.Println(b.String())
}
複製代碼