• 技术文章 >后端开发 >Golang

    go语言中list怎么删除元素

    青灯夜游青灯夜游2023-01-16 10:59:09原创58

    在go语言中,可以使用remove()函数来删除list元素,语法“list对象.Remove(element)”,参数element表示要删除列表元素。element元素不能为空,如果不为空则返回被删除的元素的值,如果为空则会报异常。

    本教程操作环境:windows7系统、GO 1.18版本、Dell G3电脑。

    go提供了一个list包,类似python的list,可以存储任意类型的数据,并提供了相应的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()函数用于列表list删除元素,删除的元素不能为空,如果为空,会报异常。

    Remove(e *Element) interface{}
    参数描述
    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)
    	}
    }

    1.png

    分析:

    示例2:删除空元素

    package main
    import (
    	"container/list"
    	"fmt"
    )
    func main() {
    	//使用 Remove 在列表中删除空元素,报错
    	listHaiCoder := list.New()
    	listHaiCoder.PushFront("Hello")
    	listHaiCoder.PushFront("HaiCoder")
    	listHaiCoder.Remove(nil)
    }

    程序运行后,控制台输出如下:

    2.png

    扩展知识:list删除所有元素

    借助list包提供的API,list用起来确实挺方便,但是在使用过程中,如果不注意就会遇到一些难以发现的坑,导致程序结果不是预想的那样。这里要说的坑是通过for循环遍历list,并删除所有元素时会遇到的问题。例如,下面这个示例程序创建了一个list,并依次将0-3存入,然后通过for循环遍历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,和最初设想不一样,按照go的使用习惯,遍历一个list并删除所有元素写法应该如下:

    for e := l.Front(); e != nil; e = e.Next() {
        l.Remove(e)
    }

    但是根据上面示例代码的输出,这样删除list所有元素是无效的,那么问题出在哪呢?由for循环的机制可以知道,既然删除了第一个元素,没有删除第二个元素,肯定是第二次循环的条件无效,才导致循环退出,即执行完下面语句后:

    l.Remove(e)

    e应该为nil,所以循环退出。在for循环中的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

    可以看到,确实只循环了一次,循环就结束了。即当执行完语句l.Remove(e)后,e等于e.Next(),因为e.Next()为nil,导致e为nil,循环退出。为什么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
    }

    由源码中可以看到,当执行l.Remove(e)时,会在内部调用l.remove(e)方法删除元素e,为了避免内存泄漏,会将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中的所有元素已经被正确删除。

    【相关推荐:Go视频教程编程教学

    以上就是go语言中list怎么删除元素的详细内容,更多请关注php中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    专题推荐:go语言 Golang
    上一篇:go语言怎么获取map元素 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • go语言中字符串怎么遍历• go语言中数组与切片有什么区别• go语言怎么比较字符串• golang怎么添加list元素• go语言怎么获取list长度• golang循环遍历map的方式有几种
    1/1

    PHP中文网