Go 中的字符串值得特別關注,與其餘語言相比,Go 中的字符串實現方式有所不一樣。html
在Go中,使用雙引號 ""
聲明字符串:golang
s := "Hello world"
fmt.Println("len(s):",len(s))
fmt.Println(s);
複製代碼
輸出:函數
len(s): 11
Hello world
複製代碼
上面的代碼聲明瞭字符串 s
,len
函數返回字符串 s
的字節數(包括空格)。在 Go 中,字符串實際上是隻讀的字節切片。post
s := "Hello world"
for i:=0;i<len(s);i++ {
fmt.Print(s[i]," ")
}
複製代碼
你以爲上面的代碼會輸出什麼,是一個個字母嗎?其實不是:學習
72 101 108 108 111 32 119 111 114 108 100
複製代碼
輸出的是每一個字母在 ASCII 碼錶上對應的十進制數字。 正如你們熟知的,Go 語言採用 UTF-8
編碼,這種編碼方式與 ASCII
編碼兼容,只不過 ASCII
編碼只需 1 個字節,而 UTF-8
須要 1-4 個字節表示一個符號。ui
s := "Hello world"
for i:=0;i<len(s) ;i++ {
fmt.Printf("%c ",s[i])
}
fmt.Println("")
for i:=0;i<len(s) ;i++ {
fmt.Printf("%v ",s[i])
}
fmt.Println("")
for i:=0;i<len(s) ;i++ {
fmt.Printf("%x ",s[i])
}
fmt.Println("")
for i:=0;i<len(s) ;i++ {
fmt.Printf("%T ",s[i])
}
複製代碼
輸出:編碼
H e l l o w o r l d
72 101 108 108 111 32 119 111 114 108 100
48 65 6c 6c 6f 20 77 6f 72 6c 64
uint8 uint8 uint8 uint8 uint8 uint8 uint8 uint8 uint8 uint8 uint8
複製代碼
上面的代碼,%v
格式化輸出字節對應的十進制值;%x
以十六進制輸出;%T
格式化輸出值的類型。從結果能夠看出,值的類型都是 uint8
即 byte
類型,byte
是 uint8
的別名,byte
類型在個人文章中有所介紹。 咱們來看下:一個字符串中包含非 ASCII
碼的字符 會是怎樣的狀況。spa
s := "Hellõ World"
fmt.Println("len(s):", len(s))
for i := 0; i < len(s); i++ {
fmt.Printf("%c ", s[i])
}
fmt.Println("")
for i := 0; i < len(s); i++ {
fmt.Printf("%v ", s[i])
}
fmt.Println("")
for i := 0; i < len(s); i++ {
fmt.Printf("%x ", s[i])
}
複製代碼
輸出:.net
len(s): 12
H e l l à µ W o r l d
72 101 108 108 195 181 32 87 111 114 108 100
48 65 6c 6c c3 b5 20 57 6f 72 6c 64
複製代碼
上面的例子中,將 o
替換成 õ
。從結果能夠看出,字符串的字節長度是 12 ,說明 õ
佔用兩個字節。然而 õ
的輸出變成了 Ã µ
, õ
的 Unicode
碼點是 U+00F5
,其 UTF-8 編碼 佔兩個字節 c3
、b5
。for
循環按字節讀取,c3
(十進制 195 )對應字符 Ã
, b5
(十進制 181 )對應字符 µ
(詳見這裏)。 熟悉 ASCII
、UTF-8
和 Unicode
更有利於理解這些知識,關於這些知識,不會在本文展開細講,有興趣的能夠參考這裏。 UTF-8
編碼中,一個碼點佔用至少一字節,若是咱們仍是以一個碼點佔用一個字節去打印字符確定會出問題,就像上面的例子同樣。那有沒有辦法解決這個問題,好在 Go 爲咱們提供了 rune
。code
rune
是 Go 的內置數據類型,是 int32
的別名,表示 Go 中的 Unicode
代碼點。用 rune
數據類型,開發人員就沒必要關心代碼點佔用幾個字節了。
s := "Hellõ World"
r := []rune(s)
fmt.Println("len(r):", len(r))
for i := 0; i < len(r); i++ {
fmt.Printf("%c ", r[i])
}
fmt.Println("")
for i := 0; i < len(r); i++ {
fmt.Printf("%v ", r[i])
}
fmt.Println("")
for i := 0; i < len(r); i++ {
fmt.Printf("%x ", r[i])
}
fmt.Println("")
for i := 0; i < len(r); i++ {
fmt.Printf("%T ", r[i])
}
複製代碼
輸出:
len(r): 11
H e l l õ W o r l d
72 101 108 108 245 32 87 111 114 108 100
48 65 6c 6c f5 20 57 6f 72 6c 64
int32 int32 int32 int32 int32 int32 int32 int32 int32 int32 int32
複製代碼
上面的代碼,字符串 s
經過類型轉化成了 rune
切片。 õ
的 Unicode
碼點就是 U+00F5
,對應十進制的 245 ,參考這。切片 r
的長度就是:11 ;輸出的 int32
,印證了 rune
是 int32
的別名。
for range
字符串上面的例子已經很好解決了以前遇到的問題,有種更好的方式 -- range string
。使用 range
循環一個字符串,將返回 rune
類型的字符和字節索引。
s := "HellõWorld"
for index, char := range s {
fmt.Printf("%c starts at byte index %d \n", char,index)
}
複製代碼
輸出:
H starts at byte index 0
e starts at byte index 1
l starts at byte index 2
l starts at byte index 3
õ starts at byte index 4
W starts at byte index 6
o starts at byte index 7
r starts at byte index 8
l starts at byte index 9
d starts at byte index 10
複製代碼
從輸出結果能夠看出,õ
佔用了兩個字節:索引 4 和 5。
文章讀到這,可能會有個疑問,怎麼獲取字符串的長度呢?
可使用 RuneCountInString()
函數,原型是這樣的:
func RuneCountInString(s string) (n int) 複製代碼
返回字符串中 rune
字符的個數。
s := "Hellõ 中國"
length := utf8.RuneCountInString(s)
fmt.Println(length)
複製代碼
輸出:8
前面咱們已經說過,字符串是隻讀的字節切片,一旦建立,是不可更改的。若是強制修改,就會報錯:
s := "Hello World"
s[0] = "h"
複製代碼
報錯:cannot assign to s[0]
這篇文章有幾點比較重要:
rune
表示 Go 中的 Unicode
代碼點;UTF-8
編碼,這種編碼方式是 Unicode
的實現方式之一;ASCII
、UTF-8
和 Unicode
,能夠參考 這,更有利於理解這篇文章;但願這篇文章可以解決你對 Go string
的一些疑問,有不懂的能夠留言討論!
原創文章,若需轉載請註明出處!
歡迎掃碼關注公衆號「Golang來啦」或者移步 seekload.net ,查看更多精彩文章。
公衆號「Golang來啦」給你準備了一份神祕學習大禮包,後臺回覆【電子書】領取!