本文系第十五篇Golang語言學習教程
什麼是字串
Go 語言中的字串是一個位元組切片. 把內容放在雙引號之間, 就可以建立一個字串.
package mainimport "fmt"func main() { name := "hello world" fmt.Println(name)}
程式輸出:hello world
Go 中字串是相容 Unicode 編碼的, 並且使用 UTF-8 進行編碼.
單獨擷取字串的每一個位元組
由於字串是位元組切片, 所以可以擷取字串的每一個位元組.
package mainimport "fmt"func printbytes(s string) { //定義函數 for i := 0; i < len(s); i++ { //len(s) 返回字串中字元的數量 fmt.Printf( "%x ", s[i]) //%x 指定列印字串的16進位編碼 }}func printchars(s string) { for i := 0; i< len(s); i++ { fmt.Printf("%c ", s[i]) //%c 指定列印字串的字元 }}func main() { name := "hello world" printbytes(name) fmt.Println("\n") printchars(name)}
上面程式中, len(s) 用於返回字串的字元數量, %x 指定列印字串的16進位編碼, %c 用於指定列印字串的數量.
以上程式輸出為:
68 65 6c 6c 6f 20 77 6f 72 6c 64
h e l l o w o r l d
上面的程式擷取字串的每一個字元,雖然看起來是合法的,但卻有一個嚴重的 bug。讓我拆解這個代碼來看看我們做錯了什麼。
package mainimport "fmt"func printbytes(s string) { //定義函數 for i := 0; i < len(s); i++ { //len(s) 返回字串中字元的數量 fmt.Printf( "%x ", s[i]) //%x 指定列印字串的16進位編碼 }}func printchars(s string) { for i := 0; i< len(s); i++ { fmt.Printf("%c ", s[i]) //%c 指定列印字串的字元 }}func main() { name := "hello world" printbytes(name) fmt.Println("\n") printchars(name) name = "Señor" fmt.Println("\n") printchars(name)}
以上程式中,我們嘗試輸出 Señor 的字元,但卻輸出了錯誤的 S e à ± o r。 為什麼程式分割 Hello World
時表現完美,但分割 Señor
就出現了錯誤呢?這是因為 ñ
的 Unicode 代碼點(Code Point)是 U+00F1
。它的 UTF-8 編碼佔用了 c3 和 b1 兩個位元組。它的 UTF-8 編碼佔用了兩個位元組 c3 和 b1。而我們列印字元時,卻假定每個字元的編碼只會佔用一個位元組,這是錯誤的。在 UTF-8 編碼中,一個代碼點可能會佔用超過一個位元組的空間。那麼我們該怎麼辦呢?rune 能幫我們解決這個難題。
rune
rune 是 Go 語言的內建類型,它也是 int32 的別稱。在 Go 語言中,rune 表示一個代碼點。代碼點無論佔用多少個位元組,都可以用一個 rune 來表示。讓我們修改一下上面的程式,用 rune 來列印字元。
package mainimport "fmt"func printbytes(s string) { //定義函數 for i := 0; i < len(s); i++ { //len(s) 返回字串中字元的數量 fmt.Printf( "%x ", s[i]) //%x 指定列印字串的16進位編碼 }}func printchars(s string) { runes := []rune(s) //字串被轉化為一個 rune 切片 for i := 0; i< len(s); i++ { fmt.Printf("%c ", runes[i]) //%c 指定列印字串的字元 }}func main() { name := "hello world" printbytes(name) fmt.Println("\n") printchars(name) name = "Señor" fmt.Println("\n") printchars(name)}
以上程式中, 將字串轉化為一個 rune 的切片.
程式輸出為:
68 65 6c 6c 6f 20 77 6f 72 6c 64
h e l l o w o r l d
S e ñ o r
字串是不可變的
Go中的字串是不可變的, 一旦建立無法更改:
package mainimport ( "fmt")func mutate(s string)string { s[0] = 'a'//any valid unicode character within single quote is a rune return s}func main() { h := "hello" fmt.Println(mutate(h))}
以上程式中想要把 h 的第一個字元變成 a, 卻報錯:main.go:8: cannot assign to s[0]
, 由此可以看出,字串不允許修改.
為了修改字串,可以把字串轉化為一個 rune 切片。然後這個切片可以進行任何想要的改變,然後再轉化為一個字串。
package mainimport ( "fmt")func mutate(s []rune) string { s[0] = 'a' return string(s)}func main() { h := "hello" fmt.Println(mutate([]rune(h)))}
以上程式中, 函數 mutate 接收到一個 rune 切片的傳入, 將第一個字元更改為 a , 然後轉換為字串輸出. 所以以上程式輸出為: aello
以上為學習Golang 字串篇