《Go語言四十二章經》第十章 string
《Go語言四十二章經》第十章 string
作者:李驍
10.1 有關string
Go 語言中的string型別儲存的字串是不可變的, 如果要修改string內容需要將string轉換為[]byte或[]rune,並且修改後的string內容是重新分配的。
那麼byte和rune的區別是什麼(下面寫法是type別名):
type byte = uint8 type rune = int32
string 型別的零值為長度為零的字串,即空字串 ""。
一般的比較運算子(==、!=、<、<=、>=、>)通過在記憶體中按位元組比較來實現字串的對比。你可以通過函式 len() 來獲取字串所佔的位元組長度,例如:len(str)。
字串的內容(純位元組)可以通過標準索引法來獲取,在中括號 [] 內寫入索引,索引從 0 開始計數:
字串 str 的第 1 個位元組:str[0] 第 i 個位元組:str[i - 1] 最後 1 個位元組:str[len(str)-1]
需要注意的是,這種轉換方案只對純 ASCII 碼的字串有效。
注意事項:
獲取字串中某個位元組的地址的行為是非法的,例如:&str[i]。
10.2 字串拼接
可以通過以下方式來對程式碼中多行的字串進行拼接。
- 直接使用運算子
str := "Beginning of the string " + "second part of the string"
由於編譯器行尾自動補全分號的緣故,加號 + 必須放在第一行。 拼接的簡寫形式 += 也可以用於字串:
s := "hel" + "lo, " s += "world!" fmt.Println(s) // 輸出 “hello, world!”
裡面的字串都是不可變的,每次運算都會產生一個新的字串,所以會產生很多臨時的無用的字串,不僅沒有用,還會給 gc 帶來額外的負擔,所以效能比較差。
- fmt.Sprintf()
fmt.Sprintf("%d:%s", 2018, "年")
內部使用 []byte 實現,不像直接運算子這種會產生很多臨時的字串,但是內部的邏輯比較複雜,有很多額外的判斷,還用到了 interface,所以效能一般。
- strings.Join()
strings.Join([]string{"hello", "world"}, ", ")
Join會先根據字串陣列的內容,計算出一個拼接之後的長度,然後申請對應大小的記憶體,一個一個字串填入,在已有一個數組的情況下,這種效率會很高,但是本來沒有,去構造這個資料的代價也不小。
- bytes.Buffer
var buffer bytes.Buffer buffer.WriteString("hello") buffer.WriteString(", ") buffer.WriteString("world") fmt.Print(buffer.String())
這個比較理想,可以當成可變字元使用,對記憶體的增長也有優化,如果能預估字串的長度,還可以用 buffer.Grow() 介面來設定 capacity。
- strings.Builder
var b1 strings.Builder b1.WriteString("ABC") b1.WriteString("DEF") fmt.Print(b1.String())
strings.Builder 內部通過 slice 來儲存和管理內容。slice 內部則是通過一個指標指向實際儲存內容的陣列。strings.Builder 同樣也提供了 Grow() 來支援預定義容量。當我們可以預定義我們需要使用的容量時,strings.Builder 就能避免擴容而建立新的 slice 了。strings.Builder是非執行緒安全,效能上和 bytes.Buffer 相差無幾。
本書《Go語言四十二章經》內容在github上同步地址:https://github.com/ffhelicopter/Go42 本書《Go語言四十二章經》內容在簡書同步地址:https://www.jianshu.com/nb/29056963