Go 的 strings 包定義了一個 Builder 型別,它有一個 String() 方法
func (b *Builder) String() string {
return *(*string)(unsafe.Pointer(&b.buf))
}
正如 reflect pacakge 所指出的,一個位元組切片被定義為一個 SliceHeader 和一個由 header 的 Data 欄位指向的關聯資料塊:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
并且 string 被定義為一個 StringHeader 和一個由 header 的 Data 欄位指向的關聯資料塊
type StringHeader struct {
Data uintptr
Len int
}
SliceHeader 有 3 個欄位(Data、Len 和 Cap),而 StringHeader 只有 2 個(Data 和 Len),那么如何直接將位元組切片轉換為字串呢?
*(*string)(unsafe.Pointer(&buf))
據我了解,我們應該撰寫以下代碼:
func byte2str(b []byte) string {
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&b))
return *(*string)(unsafe.Pointer(&reflect.StringHeader{Data: hdr.Data, Len: hdr.Len}))
}
uj5u.com熱心網友回復:
讓我們分解一下。
運算式&buf是指向切片頭的指標。指向切片的指標是指向切片頭的指標。
表達(unsafe.Pointer(&buf)是轉換從片頭指標到一個unsafe.Pointer。unsafe.Pointer 型別有一個神奇的屬性——它可以與任何其他指標型別相互轉換。
運算式是(*string)(unsafe.Pointer(&buf))從切片頭指標到字串頭指標的轉換。指向字串的指標是指向標頭的指標。
此時,我們有一個字串頭指標,它實際上指向一個切片頭。乍一看,這似乎很糟糕,但一切都很好。字串頭的記憶體布局是切片頭的記憶體布局的前綴。
該運算式*(*string)(unsafe.Pointer(&buf))取消參考字串頭指標以獲取字串。此操作將資料和長度欄位從切片標頭復制到字串標頭。
如果切片頭欄位被重新排序而沒有對字串頭欄位進行相應的更改,則此代碼將中斷,但這永遠不會發生。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/407113.html
標籤:
上一篇:WPF中帶有TextBox的TreeViewItem:單擊TextBox時如何選擇包含TextBox的TreeViewItem
