這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
首先看下以下例子:
package main
import "fmt"
func main(){
s := "我是中國人"
for i:=0; i < len(s); i++{
fmt.Printf("%c", s[i])
}
fmt.Printf("\n")
for _, v := range s {
fmt.Printf("%c", v)
}
fmt.Print("\n")
}
輸出結果:
ææ¯ä¸å½äºº
我是中國人
通過len(s)和range遍曆訪問字串元素有什麼不同嗎?
首先來複習一下go語言的字串表示,go語言有以下兩種表示字串的方法:
1、雙引號,如:“gogogo\n”,使用逸出字元
2、反引號,如:`gogogo\n`,不使用逸出字元,字串的內容將和賦值保持嚴格一致
在go語言中,沒有字元類型,rune就是字元類型
Go 語言中的字串是以 UTF-8 格式編碼並儲存的,例如:
s := "Hello 世界!"
變數 s 中存放的是這個字串的 UTF-8 編碼,當你使用 len(s) 函數擷取字串的長度時,擷取的是該字串的 UTF-8 編碼長度。通常我們認為,在電腦中儲存一個 ASCII 字元需要一個位元組,儲存一個非 ASCII 字元需要兩個位元組,這種認為僅僅是針對 Windows 系統中常用的 ANSI 編碼而言的,而在 Go 語言中,使用的是 UTF-8 編碼,用 UTF-8 編碼來存放一個 ASCII 字元依然只需要一個位元組,而存放一個非 ASCII 字元,則需要 2個、3個、4個位元組,它是不固定的。
既然 Go 中的字串存放的是 UTF-8 編碼,那麼我們使用 s[0] 這樣的下標方式擷取到的內容就是 UTF-8 編碼中的一個位元組。對於非 ASCII 字元而言,這樣的一個位元組沒有實際的意義,除非你想編碼或解碼 UTF-8 位元組流。而在 Go 語言中,已經有很多現成的方法來編碼或解碼 UTF-8 位元組流了。
遍曆字串中的位元組(使用下標訪問):
func main() {
s := "Hello 世界!"
for i, l := 0, len(s); i < l; i++ {
fmt.Printf("%2v = %v\n", i, s[i]) // 輸出單個位元組值
}
}
遍曆字串中的字元(使用 for range 語句訪問):
func main() {
s := "Hello 世界!"
for i, v := range s { // i 是字元的位元組位置,v 是字元的拷貝
fmt.Printf("%2v = %c\n", i, v) // 輸出單個字元
}
}
在 Go 語言中,字串的內容是不能修改的,也就是說,你不能用 s[0] 這種方式修改字串中的 UTF-8 編碼,如果你一定要修改,那麼你可以將字串的內容複寫到一個可寫的緩衝區中,然後再進行修改。這樣的緩衝區一般是 []byte 或 []rune。如果要對字串中的位元組進行修改,則轉換為 []byte 格式,如果要對字串中的字元進行修改,則轉換為 []rune 格式,轉換過程會自動複製資料。
修改字串中的位元組(用 []byte):
func main() {
s := "Hello 世界!"
b := []byte(s) // 轉換為 []byte,自動複製資料
b[5] = ',' // 修改 []byte
fmt.Printf("%s\n", s) // s 不能被修改,內容保持不變
fmt.Printf("%s\n", b) // 修改後的資料
}
修改字串中的字元(用 []rune):
func main() {
s := "Hello 世界!"
r := []rune(s) // 轉換為 []rune,自動複製資料
r[6] = '中' // 修改 []rune
r[7] = '國' // 修改 []rune
fmt.Println(s) // s 不能被修改,內容保持不變
fmt.Println(string(r)) // 轉換為字串,又一次複製資料
}
在 []byte 中處理 Rune 字元(需要用到 utf8 包中的解碼函數)
func main() {
b := []byte("Hello 世界!")
for len(b) > 0 {
r, n := utf8.DecodeRune(b) // 解碼 b 中的第一個字元
fmt.Printf("%c\n", r) // 顯示讀出的字元
b = b[n:] // 丟棄已讀取的字元
}
}