背景
去面試的時候遇到一道和 string 相關的題目,記錄一下用到的知識點。題目如下:
s:="123"
ps:=&s
b:=[]byte(s)
pb:=&b
s+="4"
*ps+="5"
(*pb)[1] = 0
(*pb)[2] = 4
fmt.Printf("%+v\n",*ps)
fmt.Printf("%+v\n",*pb)
問以上代碼的輸出是什么。
分析
很容易可以看出 s 和 ps 代表同一個 string,b 和 pb 代表同一個 byte 的切片。關鍵在於
b:=[]byte(s)
根據 The Go Programming Language 的解釋:
A string contains an array of bytes that, once created, is immutable. By contrast, the elements of a byte slice can be freely modified.
Strings can be converted to byte slices and back again:s := “abc”
b := []byte(s)
s2 := string(b)Conceptually, the []byte(s) conversion allocates a new byte array holding a copy of the bytes of s, and yields a slice that references the entirety of that array. An optimizing compiler may be able to avoid the allocation and copying in some cases, but in general copying is required to ensure that the bytes of s remain unchanged even if those of b are subsequently modified. The conversion from byte slice back to string with string(b) also makes a copy, to ensure immutability of the resulting string s2.
因為 string 是不可變的,所以不管是從 string 轉到 []byte 還是從 []byte 轉換到 string 都會發生一次復制。因此 p 和 b 可以看作兩個內容相同的兩個對象,對 p,b各自的修改不會影響對方。
先看 ps,經過兩次拼接后就是 "12345"。
再看 pb,因為 s 中的內容都是 ASCII 字符,在 b 中只需要用一個 byte 就可以表示一個字符,所以 b 的實際內容是[49,50,51],分別對應1,2,3的 ASCII 編碼。經過就修改后就變成了[49,0,4]。
答案
經過上面的分析,最后輸出的答案是"12345"和[49,0,4]
延伸
題目中對字符串的拼接也是常用的場景。因為 string 是不可變的,所以在拼接字符串時實際上也是將源字符串復制了一次,所以在 string 比較大時會消耗不少的內存和時間。關於字符串拼接的各種方法這里不詳細展開了,有興趣的可以參考以下幾個鏈接:
https://gocn.io/question/265
https://gocn.io/article/704
Reference
https://blog.golang.org/strings
https://sheepbao.github.io/post/golang_byte_slice_and_string/
http://nanxiao.me/golang-string-byte-slice-conversion/