別亂用了,用新的。Go SliceHeader 和 StringHeader 將會被廢棄!
大家好,我是煎魚。
Go 語言中有個很經典的 (Slice|String)Header,經常出現在大家視野中,為此我寫了《Go SliceHeader 和 StringHeader,你知道嗎?》給大家介紹,避免被面試官卷到。
以重點來講,SliceHeader 是 Slice(切片)的執行時表現;StringHeader 是 String(字串)的執行時表現。
背景
為什麼這兩個執行時結構體受到了那麼多的關注呢?是因為常被用於如下場景:
將 []byte 轉換為 string。 將 string 轉換為 []byte。 抓取資料指標(data pointer)欄位用於 ffi 或其他用途。 將一種型別的 slice 轉換為另一種型別的 slice。
常見案例,可見如下程式碼:
s := "腦子進煎魚了?重背面試題(doge"
h := (*reflect.StringHeader)(unsafe.Pointer(&s))
又或是自己構造一個:
unsafe.Pointer(&reflect.StringHeader{
Data: uintptr(unsafe.Pointer(&s.Data[0])),
Len: int(s.Size),
})
似乎看起來沒什麼問題,所以在業內開啟了一種新的姿勢。那就是藉助 (String|Slice) Header 來實現零複製的 string 到 bytes 的轉換,得到了廣大開發者的使用。畢竟誰都想效能高一點。
如下轉換程式碼:
func main() {
s := "腦子進煎魚了"
v := string2bytes1(s)
fmt.Println(v)
}
func string2bytes1(s string) []byte {
stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))
var b []byte
pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))
pbytes.Data = stringHeader.Data
pbytes.Len = stringHeader.Len
pbytes.Cap = stringHeader.Len
return b
}
當然,還有更多基於 Header 自己寫的轉換,甚至寫錯寫到洩露沒法被 GC 的,又或是丟擲 throw 致命錯誤查了幾周的。
問題
今年 Go 團隊進行了討論,透過分析、搜尋發現 reflect.SliceHeader
和 reflect.StringHeader
在業內經常被濫用,且使用不方便,很容易出錯(要命的是很隱性的那種)。
GitHub 搜尋發現大量使用者案例:
這個坑也在於,SliceHeader 和 StringHeader 的 Data 欄位(後稱資料指標):
type StringHeader struct {
Data uintptr
Len int
}
型別是 uintptr不是 unsafe.Pointer。設什麼都可以,靈活度過於高,非常容易搞出問題。
Go1.20 新特性
在 Go1.20 起,在 unsafe 標準庫新增了 3 個函式來替代前面這兩個型別的使用。希望能夠進一步標準化,並提供額外的型別安全。
如下函式簽名:
func String(ptr *byte, len IntegerType) string
:根據資料指標和字元長度構造一個新的 string。func StringData(str string) *byte
:返回指向該 string 的位元組陣列的資料指標。func SliceData(slice []ArbitraryType) *ArbitraryType
:返回該 slice 的資料指標。
新版本的用法將會變成:
func StringToBytes(s string) []byte {
return unsafe.Slice(unsafe.StringData(s), len(s))
}
func BytesToString(b []byte) string {
return unsafe.String(&b[0], len(b))
}
以往常用的 reflect.SliceHeader
和 reflect.StringHeader
將會被標註為被廢棄。
如下圖:
這兩個型別老版本中一直被標記為不穩定、不可靠。
以後記得換用法了。
總結
StringHeader 和 SliceHeader 在工作中的底層工具包在前兩年非常常見,如果是一個積累比較久的專案可能在內部都偷偷引用了,目的就是為了讓自己的效能跑分更優一些。
但是其較大的自由度,帶來了過大的型別不安全。因此我在工作中也遇到有人用到莫名其妙拋致命錯誤,最後只能用排除法去查是哪裡的鍋。
在新版本 Go1.20 中,Go 官方引入了這幾個新函式。能夠進一步宣告這是 unsafe 的,也能提供一點點的型別安全檢查。
當然,新版本後,愛問這幾個零複製的面試官,也得重新整理一下知識庫了。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024923/viewspace-2928845/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Go SliceHeader 和 StringHeader,你知道嗎?GoHeader
- Node.js 最早 npm 包 request 將被廢棄Node.jsNPM
- PHP7.4 新特性和廢棄的功能PHP
- go操作redis(已經廢棄)GoRedis
- Android:7.0 後加密庫 Crypto 被廢棄Android加密
- java.util.Date會被棄用嗎?Java
- 蘋果大掃除 App Store應用商店將清理廢棄軟體蘋果APP
- 一些Julia 0.4版中有,被高版本廢棄的功能
- 被嫌棄的eval和with
- Go語言slice的本質-SliceHeaderGoHeader
- kotlin-android-extensions外掛也被廢棄了KotlinAndroid
- K8S 棄用 Docker 了?Docker 不能用了?別逗了!K8SDocker
- 將在版本11.2之後廢棄或不再支援的特性
- Vue 插槽 廢棄語法Vue
- 別讓自己成為一名廢棄的程式設計師程式設計師
- Java序列化技術即將被廢除!!!Java
- 被廣泛使用的OAuth2.0的密碼模式已經廢了,放棄吧OAuth密碼模式
- 觸控識別技術將被智慧機拋棄?它還能應用於這些安全系統識別
- Table被web程式設計棄用的原因Web程式設計
- Go1.18 新特性:棄用 strings.Title 方法,換個新坑吧!Go
- MySQL 8.0.20 安裝新特性以及一些廢棄引數MySql
- 【轉】oracle 10G中log_archive_start引數已經被廢棄Oracle 10gHive
- 3-13. HTML中被廢棄的標籤HTML
- iOS 官方巨集定義 - “引入”、“廢棄”iOS
- ”被棄者“
- go的 & 和 * 的區別,以及應用場景Go
- 《學習筆記》被廢棄的Kotlin Android Extensions外掛替代品 View Binding筆記KotlinAndroidView
- chrome + vi 純手工模式, 廢棄滑鼠。Chrome模式
- Android startActivityForResult()廢棄了,代替方案案例Android
- 棄用!Github 上用了 Git.io 縮址服務的都注意了Github
- 應用號即將“駕到”,APP會被取而代之嗎?APP
- Go高階特性 17 | SliceHeader:slice 高效處理資料GoHeader
- getOriginal()被廢棄?改為:getRawOriginal()新手剛遇到,提醒和我一樣的新手!!
- 能源驅動的 AI 將會被用來解決能源問題AI
- php5.5CURL圖片上傳廢棄@PHP
- Pixelate:蘋果和Google的應用商店包括超過150萬個”被遺棄的應用”蘋果Go
- 前端開發入門到實戰:HTML5新增和廢棄的標籤前端HTML
- 被遺棄的執行緒執行緒