歡迎訪問我的個(gè)人網(wǎng)站獲取更佳閱讀排版:Go語言源碼閱讀(4) - container/list | 鏈表 | yoko blog (https://pengrl.com/p/51973/)
是雙向鏈表。
實(shí)現(xiàn)上,有哨兵root節(jié)點(diǎn),即當(dāng)鏈表為空時(shí),還有一個(gè)哨兵元素。
實(shí)現(xiàn)多態(tài)的方式是Element結(jié)構(gòu)體內(nèi)有一個(gè)interface{}數(shù)據(jù)成員,可以用來存儲(chǔ)任意類型的數(shù)據(jù)。其余鏈表和鏈表元素的代碼都是系統(tǒng)庫(kù)提供的。
container/list/example_test.go演示了如何申請(qǐng)一個(gè)List,并對(duì)它進(jìn)行一些插入操作后,如何遍歷訪問該List。
有一點(diǎn)非常值得思考,就是Go語言沒有構(gòu)造函數(shù),從而導(dǎo)致的一些問題。
當(dāng)一個(gè)結(jié)構(gòu)體變量在使用前需要對(duì)它的數(shù)據(jù)成員做一些非zero out的初始化時(shí)(Go語言會(huì)對(duì)所有數(shù)據(jù)成員做zero out),
要么是提供一個(gè)New接口,接口返回一個(gè)結(jié)構(gòu)體的指針類型,內(nèi)部實(shí)現(xiàn)是實(shí)例化結(jié)構(gòu)體變量后,然后做Init操作。但是從語意上來講,這種變量是分配在堆上的。
要么是提供一個(gè)Init接口,壞處是要么用戶在棧上聲明了結(jié)構(gòu)體變量時(shí),還需要手動(dòng)調(diào)用Init函數(shù),增加了使用時(shí)成本。要么是在其他的方法內(nèi)部做lazy init,這又增加了結(jié)構(gòu)體的實(shí)現(xiàn)復(fù)雜度,以及小小的性能(畢竟lazy init每次都要判斷是否已經(jīng)init了)。
List提供的對(duì)外接口有:
常規(guī)操作:
// 初始化List,這個(gè)接口并不是在使用List前非調(diào)用不可的,因?yàn)椴糠諰ist的操作會(huì)在操作前判斷List是否已經(jīng)Init并做懶初始化
// 如果先清空一個(gè)List,也可以對(duì)List調(diào)用Init方法
func (l *List) Init() *List
// 返回一個(gè)*List變量
func New() *List
// 獲取List的長(zhǎng)度
// List中會(huì)持續(xù)記錄更新數(shù)據(jù)成員len,所以獲取長(zhǎng)度的復(fù)雜度是`O(1)`的。
func (l *List) Len() int
// 獲取頭部元素
func (l *List) Front() *Element
// 獲取尾部元素
func (l *List) Back() *Element
// 頭部插入
func (l *List) PushFront(v interface{}) *Element
// 尾部插入
func (l *List) PushBack(v interface{}) *Element
// 某個(gè)元素前插入
func (l *List) InsertBefore(v interface{}, mark *Element) *Element
// 某個(gè)元素后插入
func (l *List) InsertAfter(v interface{}, mark *Element) *Element
// 刪除某個(gè)元素
func (l *List) Remove(e *Element) interface{}
wrap類型的操作,對(duì)常規(guī)操作做的組合封裝:
// 將某個(gè)元素移動(dòng)到頭部
func (l *List) MoveToFront(e *Element)
// 將某個(gè)元素移動(dòng)到尾部
func (l *List) MoveToBack(e *Element)
// 將某個(gè)元素<e>移動(dòng)到另一個(gè)元素<mark>的前面,注意,只是移動(dòng)e,不移動(dòng)mark
func (l *List) MoveBefore(e, mark *Element)
// 將某個(gè)元素移動(dòng)到另一個(gè)元素的后面
func (l *List) MoveAfter(e, mark *Element)
最后,還支持鏈表的拼接操作:
// 將<other>鏈表插入<l>鏈表之后
func (l *List) PushBackList(other *List)
// 插到前面
func (l *List) PushFrontList(other *List)
Element提供的接口:
// 可訪問的數(shù)據(jù)成員,可強(qiáng)轉(zhuǎn)成用戶存入的類型
Value interface{}
// 前一個(gè)元素
func (e *Element) Prev() *Element
// 后一個(gè)元素
func (e *Element) Next() *Element
基于Go 1.11.4