在go語言中,可以使用remove()函數(shù)來刪除list元素,語法“l(fā)ist對象.Remove(element)”,參數(shù)element表示要刪除列表元素。element元素不能為空,如果不為空則返回被刪除的元素的值,如果為空則會報異常。
本教程操作環(huán)境:windows7系統(tǒng)、GO 1.18版本、Dell G3電腦。
go提供了一個list包,類似python的list,可以存儲任意類型的數(shù)據(jù),并提供了相應(yīng)的API,如下:
type Element func (e *Element) Next() *Element func (e *Element) Prev() *Element type List func New() *List func (l *List) Back() *Element func (l *List) Front() *Element func (l *List) Init() *List func (l *List) InsertAfter(v interface{}, mark *Element) *Element func (l *List) InsertBefore(v interface{}, mark *Element) *Element func (l *List) Len() int func (l *List) MoveAfter(e, mark *Element) func (l *List) MoveBefore(e, mark *Element) func (l *List) MoveToBack(e *Element) func (l *List) MoveToFront(e *Element) func (l *List) PushBack(v interface{}) *Element func (l *List) PushBackList(other *List) func (l *List) PushFront(v interface{}) *Element func (l *List) PushFrontList(other *List) func (l *List) Remove(e *Element) interface{}
其中,remove()函數(shù)用于列表list刪除元素,刪除的元素不能為空,如果為空,會報異常。
Remove(e *Element) interface{}
參數(shù) | 描述 |
---|---|
e | 要刪除列表元素。 |
返回值
-
返回被刪除的元素的值。
列表刪除元素的示例
示例1:
package main import ( "container/list" "fmt" ) func main() { //使用 Remove 在列表中刪除元素 listHaiCoder := list.New() listHaiCoder.PushFront("Hello") listHaiCoder.PushFront("HaiCoder") element := listHaiCoder.PushFront("Hello") removeEle := listHaiCoder.Remove(element) fmt.Println("RemoveElement =", removeEle) for i := listHaiCoder.Front(); i != nil; i = i.Next() { fmt.Println("Element =", i.Value) } }
分析:
-
我們通過 list.New 創(chuàng)建了一個列表 listHaiCoder,接著使用 PushFront 函數(shù)在列表中插入三個元素,接著使用 Remove 函數(shù)刪除了最后插入的元素。
-
最后,我們打印被刪除的元素和刪除后的列表,Remove 函數(shù)返回的是被刪除的元素的值,同時,我們發(fā)現(xiàn)最后插入的元素已經(jīng)被成功從列表刪除了。
示例2:刪除空元素
package main import ( "container/list" "fmt" ) func main() { //使用 Remove 在列表中刪除空元素,報錯 listHaiCoder := list.New() listHaiCoder.PushFront("Hello") listHaiCoder.PushFront("HaiCoder") listHaiCoder.Remove(nil) }
程序運行后,控制臺輸出如下:
擴(kuò)展知識:list刪除所有元素
借助list包提供的API,list用起來確實挺方便,但是在使用過程中,如果不注意就會遇到一些難以發(fā)現(xiàn)的坑,導(dǎo)致程序結(jié)果不是預(yù)想的那樣。這里要說的坑是通過for循環(huán)遍歷list,并刪除所有元素時會遇到的問題。例如,下面這個示例程序創(chuàng)建了一個list,并依次將0-3存入,然后通過for循環(huán)遍歷list刪除所有元素:
package main import ( "container/list" "fmt" ) func main() { l := list.New() l.PushBack(0) l.PushBack(1) l.PushBack(2) l.PushBack(3) fmt.Println("original list:") prtList(l) fmt.Println("deleted list:") for e := l.Front(); e != nil; e = e.Next() { l.Remove(e) } prtList(l) } func prtList(l *list.List) { for e := l.Front(); e != nil; e = e.Next() { fmt.Printf("%v ", e.Value) } fmt.Printf("n") }
運行程序輸出如下:
original list: 0 1 2 3 deleted list: 1 2 3
從輸出可以知道,list中的元素并沒有被完全刪除,僅刪除了第一個元素0,和最初設(shè)想不一樣,按照go的使用習(xí)慣,遍歷一個list并刪除所有元素寫法應(yīng)該如下:
for e := l.Front(); e != nil; e = e.Next() { l.Remove(e) }
但是根據(jù)上面示例代碼的輸出,這樣刪除list所有元素是無效的,那么問題出在哪呢?由for循環(huán)的機(jī)制可以知道,既然刪除了第一個元素,沒有刪除第二個元素,肯定是第二次循環(huán)的條件無效,才導(dǎo)致循環(huán)退出,即執(zhí)行完下面語句后:
l.Remove(e)
e應(yīng)該為nil,所以循環(huán)退出。在for循環(huán)中的l.Remove(e)語句前添加打印語句驗證,例如添加如下語句:
fmt.Println("delete a element from list")
運行程序輸出如下:
original list: 0 1 2 3 deleted list: delete a element from list 1 2 3
可以看到,確實只循環(huán)了一次,循環(huán)就結(jié)束了。即當(dāng)執(zhí)行完語句l.Remove(e)后,e等于e.Next(),因為e.Next()為nil,導(dǎo)致e為nil,循環(huán)退出。為什么e.Next()會是nil呢?通過查看go list源碼,如下所示:
// remove removes e from its list, decrements l.len, and returns e. func (l *List) remove(e *Element) *Element { e.prev.next = e.next e.next.prev = e.prev e.next = nil // avoid memory leaks e.prev = nil // avoid memory leaks e.list = nil l.len-- return e } // Remove removes e from l if e is an element of list l. // It returns the element value e.Value. func (l *List) Remove(e *Element) interface{} { if e.list == l { // if e.list == l, l must have been initialized when e was inserted // in l or l == nil (e is a zero Element) and l.remove will crash l.remove(e) } return e.Value }
由源碼中可以看到,當(dāng)執(zhí)行l(wèi).Remove(e)時,會在內(nèi)部調(diào)用l.remove(e)方法刪除元素e,為了避免內(nèi)存泄漏,會將e.next和e.prev賦值為nil,這就是問題根源。
修正程序如下:
package main import ( "container/list" "fmt" ) func main() { l := list.New() l.PushBack(0) l.PushBack(1) l.PushBack(2) l.PushBack(3) fmt.Println("original list:") prtList(l) fmt.Println("deleted list:") var next *list.Element for e := l.Front(); e != nil; e = next { next = e.Next() l.Remove(e) } prtList(l) } func prtList(l *list.List) { for e := l.Front(); e != nil; e = e.Next() { fmt.Printf("%v ", e.Value) } fmt.Printf("n") }
運行程序輸出如下:
original list: 0 1 2 3 deleted list:
可以看見,list中的所有元素已經(jīng)被正確刪除。
【