高效使用Go中的指針

Go中的指針有兩種示启,一種是內(nèi)置類型uintptr湃密,本質(zhì)是一個整型巫员,另一種是unsafe包提供的Pointer蛾坯,表示可以指向任意類型的指針。通常uintptr用來進行指針計算疏遏,因為它是整型脉课,所以很容易計算出下一個指針所指向的位置,而unsafe.Pointer用來進行橋接财异,用于不同類型的指針進行互相轉(zhuǎn)換倘零。

Go中也提供了unsafe.Pointer和uintptr使用的一些準則。

有了這些基本概念戳寸,我們可以怎么玩呢呈驶?

通常我們將byte[]轉(zhuǎn)換成string是這樣做的:

b := byte[]("Peppa")
string(b)

這個方式有個問題,就是會分配一份內(nèi)存并進行拷貝疫鹊,更高效的方式應(yīng)該是不分配任何內(nèi)存袖瞻,在原有內(nèi)存上進行類型轉(zhuǎn)換。

slice 本質(zhì)是一個結(jié)構(gòu)體拆吆,里面含有指向底層數(shù)組的指針以及Len聋迎、Cap成員,通過reflect包可以看到slice是這樣表示的:

type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}

其中Data是指向底層數(shù)組第一個元素的指針枣耀。byte slice之所以能在原有內(nèi)存上轉(zhuǎn)換成string是因為string結(jié)構(gòu)和slice比較像霉晕,通過reflect包可以看到string是這樣表示的:

type StringHeader struct {
    Data uintptr
    Len  int
}

所以我們只要在原始內(nèi)存上構(gòu)造出來StringHeader就可以了。

sh := reflect.StringHeader{
    uintptr(unsafe.Pointer(&b[0])),
    len(b),
}

其中Data指向的是slice的第一個元素捞奕,Len是slice的長度牺堰。這里使用unsafe.Pointer進行了橋接。
創(chuàng)建好StringHeader對象颅围,下一步就是將其轉(zhuǎn)換成string類型的對象伟葫,如何做呢?還是通過unsafe.Pointer進行橋接院促。

*(*string)(unsafe.Pointer(&sh))

先將StringHeader類型的指針轉(zhuǎn)換到unsafe.Pointer筏养,然后再將unsafe.Pointer轉(zhuǎn)換成string類型的指針斧抱,最后通過指針取值獲得實際的值。
這種通過unsafe.Pointer進行類型轉(zhuǎn)換的方式在unsafe包中也進行了說明撼玄,其中舉的例子就是math包中的Float64bits方法:

func Float64bits(f float64) uint64 {
    return *(*uint64)(unsafe.Pointer(&f))
}

我們可以驗證兩種方式是否重新分配了內(nèi)存夺姑。

import (
    "github.com/davecgh/go-spew/spew"
    "unsafe"
    "reflect"
    "fmt"
)

func byteToString(b []byte) string {
    return string(b)
}

func byteToStringNoAlloc(b []byte) string {
    if len(v) == 0 {return ""}
    sh := reflect.StringHeader{uintptr(unsafe.Pointer(&b[0])), len(b)}
    return *(*string)(unsafe.Pointer(&sh))
}

func main() {
    b := []byte("Peppa")
    fmt.Println("切片第一個元素: ", spew.Sdump(&b[0]))

    str := byteToString(b)
    sh := (*reflect.StringHeader)(unsafe.Pointer(&str))
    fmt.Println("分配內(nèi)存的方式: ", spew.Sdump(sh))

    strNoAlloc := byteToStringNoAlloc(b)
    shNoAlloc := (*reflect.StringHeader)(unsafe.Pointer(&toStr))
    fmt.Println("不分配內(nèi)存的方式: ", spew.Sdump(shNoAlloc))
}

這種方式會帶來一個比較嚴重的問題墩邀,Data指向的內(nèi)存可能隨時會被回收掌猛,因為uintptr是不安全的,所以當那段內(nèi)存被回收后眉睹,這種在原始內(nèi)存上進行轉(zhuǎn)換的操作可能會導致panic荔茬,所以在使用這種方式時要保持警惕。

unsafe包也提供了安全的stringHeader和sliceHeader竹海,不過它們沒有暴露出來慕蔚,所以暫時還沒有辦法避免內(nèi)存不被回收的類型轉(zhuǎn)換。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末斋配,一起剝皮案震驚了整個濱河市孔飒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌艰争,老刑警劉巖坏瞄,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異甩卓,居然都是意外死亡鸠匀,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門逾柿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缀棍,“玉大人,你說我怎么就攤上這事机错∨婪叮” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵弱匪,是天一觀的道長坦敌。 經(jīng)常有香客問我,道長痢法,這世上最難降的妖魔是什么狱窘? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮财搁,結(jié)果婚禮上蘸炸,老公的妹妹穿的比我還像新娘。我一直安慰自己尖奔,他們只是感情好搭儒,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布穷当。 她就那樣靜靜地躺著,像睡著了一般淹禾。 火紅的嫁衣襯著肌膚如雪馁菜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天铃岔,我揣著相機與錄音汪疮,去河邊找鬼。 笑死毁习,一個胖子當著我的面吹牛智嚷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播纺且,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼盏道,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了载碌?” 一聲冷哼從身側(cè)響起猜嘱,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嫁艇,沒想到半個月后朗伶,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡裳仆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年腕让,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片歧斟。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡纯丸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出静袖,到底是詐尸還是另有隱情觉鼻,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布队橙,位于F島的核電站坠陈,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏捐康。R本人自食惡果不足惜仇矾,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望解总。 院中可真熱鬧贮匕,春花似錦、人聲如沸花枫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至敦锌,卻和暖如春馒疹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背乙墙。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工颖变, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人伶丐。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓悼做,卻偏偏與公主長得像疯特,于是被迫代替她去往敵國和親哗魂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容

  • go語言的指針類型 簡單地說go語言的指針類型和C/C++的指針類型用法是一樣的漓雅,除了出去安全性的考慮录别,go語言增...
    CodingCode閱讀 5,806評論 1 2
  • 首先巴拉巴拉一下golang反射機制的三個定律 1.反射可以從接口類型到反射類型對象 2.反射可以從反射類型對象到...
    吃貓的魚0閱讀 2,915評論 0 1
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,719評論 0 9
  • 最全的iOS面試題及答案 iOS面試小貼士 ———————————————回答好下面的足夠了-----------...
    zweic閱讀 2,702評論 0 73
  • “思維導圖 開啟你的思維崛起之路” by 麗芳老師 結(jié)束了兩天的線下課程邻吞,4月11日组题,為期一個月的線上系列課程之旅...
    知識點燈人_靜靜閱讀 5,008評論 7 26