golang二級指標操作連結串列
golang利用二級指標操作連結串列
以下所有觀點都是個人愚見,有不同建議或補充的的歡迎emial我aboutme
導讀
之前開了個專案來看golang runtime原始碼https://github.com/sheepbao/golang_runtime_reading,發現實現全域性P連結串列的程式碼挺有趣的,遂研究記錄一下。
先看個例子
package ptplist
import (
"log"
"testing"
"unsafe"
)
type puintptr uintptr
//go:nosplit
func (pp puintptr) ptr() *p { return (*p)(unsafe.Pointer(pp)) }
//go:nosplit
func (pp *puintptr) set(p *p) { *pp = puintptr(unsafe.Pointer(p)) }
type p struct {
id int
link puintptr
}
var pidleList puintptr
func pidleput(_p_ *p) {
_p_.link = pidleList
pidleList.set(_p_)
}
func pidleget() *p {
_p_ := pidleList.ptr()
if _p_ != nil {
pidleList = _p_.link
}
return _p_
}
func TestPtoPList(t *testing.T) {
for i := 0; i < 5; i++ {
tp := p{id: i}
pidleput(&tp)
log.Printf("put p: %d", i)
}
log.Println("")
for i := 0; i < 5; i++ {
tp := pidleget()
log.Printf("get p: %d", tp.id)
}
}
結果:
=== RUN TestPtoPList
2018/08/28 17:25:22 put p: 0
2018/08/28 17:25:22 put p: 1
2018/08/28 17:25:22 put p: 2
2018/08/28 17:25:22 put p: 3
2018/08/28 17:25:22 put p: 4
2018/08/28 17:25:22
2018/08/28 17:25:22 get p: 4
2018/08/28 17:25:22 get p: 3
2018/08/28 17:25:22 get p: 2
2018/08/28 17:25:22 get p: 1
2018/08/28 17:25:22 get p: 0
--- PASS: TestPtoPList (0.00s)
分析
從結果上看pidleList
實現了一個棧,pidleput
把一個新的p push到pidleList
,pidleget
是從pidleList
pop出一個p。
具體看看這個怎麼實現的:
type puintptr uintptr
首先我們定義了puintptr型別,底層型別為uintptr。uintptr是整型,可以足夠儲存指標的值得範圍,在32平臺下為4位元組,在64位平臺下是8位元組,它和unsafe.Pointer可相互轉換。 uintptr和unsafe.Pointer的區別就是:unsafe.Pointer只是單純的通用指標型別,用於轉換不同型別指標,它不可以參與指標運算;而uintptr是可用於指標運算的。
uintptr和unsafe.Pointer互轉換
func TestUintprt1(t *testing.T) {
var a int
a = 2018
b := (*int)(unsafe.Pointer(&a))
t.Logf("a.addr=%p, b.addr=%p, *b=%d", &a, b, *b)
buintptr := uintptr((unsafe.Pointer(&a)))
t.Logf("buintptr=0x%x", buintptr)
}
output:
a.addr=0xc42008e1e0, b.addr=0xc42008e1e0, *b=2018
buintptr=0xc42008e1e0
buintptr的值就等於a的地址
uintptr的指標運算取陣列
func TestUintprt2(t *testing.T) {
var a [2]int
a[0] = 2018
a[1] = 2019
t.Logf("a0.addr=%p, a1.addr=%p", &a[0], &a[1])
auintptr := uintptr((unsafe.Pointer(&a)))
t.Logf("auintptr=0x%x", auintptr)
// 把auintptr的值加上一個指標的長度, 和C語言的p++一樣
a1uintptr := auintptr + unsafe.Sizeof(&a)
a1pointer := unsafe.Pointer(a1uintptr)
// 得到a[1]
a1 := *(*int)(a1pointer)
t.Logf("a1pointer=%p, a1=%d", a1pointer, a1)
}
output:
a0.addr=0xc42009c1e0, a1.addr=0xc42009c1e8
auintptr=0xc42009c1e0
a1pointer=0xc42009c1e8, a1=2019
獲取到auintptr表示a陣列的首地址,把它加上一個指標長度,就會得到a陣列下一個元素。這個和C語言的p++是一樣的,只不過golang不推崇指標運算,寫起來很麻煩。
//go:nosplit
func (pp puintptr) ptr() *p { return (*p)(unsafe.Pointer(pp)) }
//go:nosplit
func (pp *puintptr) set(p *p) { *pp = puintptr(unsafe.Pointer(p)) }
接著給puintptr型別增加了兩個方法,比如現有有個puintptr型別的值pl,那麼:
ptr()
方法,將pl變為p型別的指標返回,set(p *p)
方法將p的地址轉換為puintptr,並將這puintptr賦值給pl,也就是說pl的值等於p的地址。
這裡的pp是pl的指標,*pl就是二級指標了。理解這兩個方法就好理解程式碼了。
func pidleput(_p_ *p) {
// 將pidleList賦值給link ,最開始的時候pidleList為0,但是之後pidleList是上個p的地址
_p_.link = pidleList
// pidleList儲存_p_的地址
pidleList.set(_p_)
}
接著定義put方法,_p_.link
儲存上個p的地址,pidleList
儲存當前_p_
的地址,這裡就構成了單向連結串列,看圖最明顯
/*
p1 p2
+-------+ +-------+
| id |<-----+ | id |<------ pidleList
+-------+ | +-------+
| link | +----| link |
+-------+ +-------+
*/
所以每當pidleput時將當前p的link指向上個p,pidleList指向最新的p
func pidleget() *p {
// 獲取pidleList指向的p
_p_ := pidleList.ptr()
// _p_ 不等於0
if _p_ != nil {
// 將pidleList重新指向下一個p
pidleList = _p_.link
}
return _p_
}
理解了上面的pidleget就簡單了。
golang 原始碼
想具體看原始碼的話可以看下面的連線:
https://github.com/sheepbao/golang_runtime_reading/blob/master/src/runtime/proc.go
https://github.com/sheepbao/golang_runtime_reading/blob/master/src/runtime/runtime2.go
相關文章
- [Golang]力扣LeetBook—初級演算法—連結串列—迴文連結串列(快慢指標)Golang力扣演算法指標
- Linus:利用二級指標刪除單向連結串列指標
- 指標和連結串列指標
- 誰說Java無指標, JAVA連結串列指標也好煩 - Java 指標迴歸Java指標
- 連結串列操作
- 連結串列以及golang介入式連結串列的實現Golang
- (轉發)連結串列新增函式中為什麼要用指向連結串列指標的指標(引用傳參)函式指標
- 連結串列面試題(二)---連結串列逆序(連結串列反轉)面試題
- 【連結串列問題】打卡8:複製含有隨機指標節點的連結串列隨機指標
- 單連結串列增刪改查(無頭指標)指標
- day4 連結串列-模擬與快慢指標指標
- 【原創】淺談指標(十)連結串列的寫法指標
- 利用快慢指標快速得到連結串列中間節點指標
- Java連結串列指標確實好煩 - 交換連結串列中連續的兩個節點的位置Java指標
- 466. 使用快慢指標把有序連結串列轉換二叉搜尋樹指標
- golang 實現連結串列爽不爽?Golang
- 實現反轉連結串列--遞迴、迭代、雙指標、棧遞迴指標
- c 連結串列之 快慢指標 查詢迴圈節點指標
- 比如,一級指標、二級指標等,通過不同層級的指標資料指標
- 二級指標做形參機制總結指標
- golang指標Golang指標
- golang 指標Golang指標
- 二叉連結串列儲存結構、二叉樹相關操作二叉樹
- 連結串列操作源程式 (轉)
- 3.2資料結構之指標和連結串列 1748:約瑟夫問題資料結構指標
- leetcode 876. 連結串列的中間結點(快慢指標法)LeetCode指標
- 資料結構實驗之連結串列二:逆序建立連結串列資料結構
- 資料結構之連結串列篇(單連結串列的常見操作)資料結構
- 資料結構之連結串列操作資料結構
- 【程式碼隨想錄】二、連結串列:2、設計連結串列
- 【程式碼隨想錄】二、連結串列:1、移除連結串列元素
- golang常用手冊:指標、結構體Golang指標結構體
- 面試 7:快慢指標法玩轉連結串列演算法面試(一)面試指標演算法
- Golang從合併連結串列聊遞迴Golang遞迴
- 單連結串列簡單操作一
- 02-單連結串列的操作
- 帶頭結點的連結串列操作題
- 初級演算法-連結串列演算法