strings-Builder 轉換字符串的時候爲什麼比 bytes-Buffer 要快
【導讀】go 的 strings Builder 和 bytes Buffser 在轉換字符串的實現上有什麼不同?本文做了詳細解析。
strings.Builder
和bytes.Buffer
底層都是[]byte
, 爲什麼strings.Builder
的 String() 方法比bytes.Buffer
的要快?
unsafe.Pointer 的用法
Pointer 類型代表了任意一種類型的指針,類型 Pointer 有四種專屬的操作:
-
任意類型的指針能夠被轉換成 Pointer 值
-
一個 Pointer 值能夠被轉換成任意類型的指針值
-
一個 uintptr 值能夠被轉換從 Pointer 值
-
一個 Pointer 值能夠被轉換成 uintptr 值
因此 Pointer 類型允許一個程序繞過類型系統,讀,寫任意內存。它應該被非常謹慎地使用
Pointer 通過特定的模式來使用。如果某些代碼不以 Go 文檔中指定的模式來使用,Go 將無法保證它在現在或者未來是有效的 下面的每個模式都有非常重要的注意事項。
運行 go vet 命令可以檢測 Pointer 的用法是否超出 Go 文檔中指定的模式, 但是 go vet 沒有檢測到異常並不代表所檢測的代碼一定是有效的。
下面我們將簡單介紹類型轉換模式,更多的模式請參考 Go Pointer 文檔
類型轉換模式
可以通過*T1 => Pointer => *T2
的方式來完成類型轉換。
需要保證 T2
的內存 <= T1
的內存,而且轉換以後它們使用的是同一片內存數據。這個轉換允許將一片內存區中的數據從一種類型變成另外一種類型。使用這個轉換的一個例子是math.Float64bits
func Float64bits(f float64) uint64 {
return *(*uint64)(unsafe.Pointer(&f))
}
針對 []byte 和 string 執行類型轉換
瞭解了類型轉換模式後,我們來看一段 []byte
轉換成 string 的代碼:
package main
import (
"fmt"
"unsafe"
)
func main() {
var b = []byte{'H', 'E', 'L', 'L', 'O'}
s := *(*string)(unsafe.Pointer(&b))
fmt.Println("b =", b)
fmt.Println("s =", s)
b[1] = 'B'
fmt.Println("s =", s)
s = "WORLD"
fmt.Println("b =", b)
fmt.Println("s =", s)
//b = [72 69 76 76 79]
//s = HELLO
//s = HBLLO
//b = [72 66 76 76 79]
//s = WORLD
}
可以看到,將b []byte
轉換成s string
後,他們還是用同一片內存空間, 所以針對 b 的改變也會影響到 s。但是對 s 重新賦值後,它們所使用的內存空間不同了,所以 s 改變後,b 並不會改變。
比較 strings.Builder 和 bytes.Buffer
strings.Builder
和bytes.Buffer
底層都是使用[]byte
實現的, 但是性能測試的結果顯示, 執行String()
函數的時候,strings.Builder
卻比bytes.Buffer
快很多。
區別就在於 bytes.Buffer
是重新申請了一塊空間,存放生成的 string 變量, 而strings.Builder
直接將底層的[]byte
轉換成了string
類型返回了回來。
在bytes.Buffer
中也說明了,如果想更有效率地 (efficiently) 構建字符串,請使用strings.Builder
類型
- bytes.Buffer
// String returns the contents of the unread portion of the buffer
// as a string. If the Buffer is a nil pointer, it returns "<nil>".
//
// To build strings more efficiently, see the strings.Builder type.
func (b *Buffer) String() string {
if b == nil {
// Special case, useful in debugging.
return "<nil>"
}
return string(b.buf[b.off:])
}
- strings.Builder
// String returns the accumulated string.
func (b *Builder) String() string {
return *(*string)(unsafe.Pointer(&b.buf))
}
轉自:bwangel
bwangel.me/2019/04/28/byte-vs-builder/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/XewWFqvHdHz45puNi_zM0Q