dqkxo44488 2018-06-20 22:44
浏览 96

如何创建包装容器/ list.List的golang结构?

I am scratching my head over an unexpected difference between having my struct contain list.List vs *list.List. Why doesn't the following work?

type listHolder struct {
    id     int
    mylist list.List
}

func newListHolder(id int, text string) listHolder {
    var newLH listHolder
    newLH.mylist = *list.New()
    newLH.id = id
    newLH.mylist.PushBack(text)
    return newLH
}

func (l *listHolder) pushBack(text string) {
    l.mylist.PushBack(text)
}

func (l *listHolder) printAll() {
    for temp := l.mylist.Front(); temp != nil; temp = temp.Next() {
        fmt.Println(temp.Value)
    }
}


func main() {
    a := newListHolder(1, "first") 
    a.pushBack("second")
    fmt.Printf("listHolder %d length %d Front()= %v, Back()=%v
",
         a.id, a.mylist.Len(), a.mylist.Front().Value, a.mylist.Back().Value)
    a.printAll()
}

This outputs the following, showing that the length is as expected but the Front() and Back() methods don't work.

listHolder 1 length 2 Front()= `<nil>`, Back()=<nil>
<nil>

If I define the struct as

// Same thing with a pointer
type listHolderPtr struct {
    id     int
    mylist *list.List
}

func newListHolderPtr(id int, text string) listHolderPtr {
    var newLH listHolderPtr
    newLH.mylist = list.New()
    newLH.id = id
    newLH.mylist.PushBack(text)
    return newLH
}

that works as expected, but of course, any copies of the listHolder struct share a reference to the same list, which is not what I want. I need to be able to copy the surrounding object and get a new copy of the internal list. Is that possible?

See https://play.golang.org/p/KCtTwuvaS1R for a simplified example of what I'm trying to do. In the real use case, I'll be pushing onto the back and popping off the front of each listHolder in a slice of listHolder in a complicated nested loop.

  • 写回答

1条回答 默认 最新

  • duanchi5078 2018-06-24 20:55
    关注

    I think @JimB's suggestion to make a local copy of your list whenever you're pushing a value to listHolder.mylist could be a good solution to your problem (given, that I understand the underlying issue correctly). I tried to come up with an implementation that looks like the following:

    package main
    
    import (
        "container/list"
        "fmt"
    )
    
    type listHolder struct {
        id     int
        mylist list.List
    }
    
    func newListHolder(id int) listHolder { // don't push back when constructing a new listHolder
        var newLH listHolder
        newLH.mylist = *list.New()
        newLH.id = id
        return newLH
    }
    
    func (l *listHolder) pushBack(text string) {
        // create a temporary list to copy all old and the new value to
        tmpList := list.New()
    
        // copy all existing values from l.mylist
        for e := l.mylist.Front(); e != nil; e = e.Next() {
            fmt.Printf("pushing back '%v' from old list
    ", e.Value)
            tmpList.PushBack(e.Value)
        }
    
        // push back the new value
        tmpList.PushBack(text)
    
        // print the new tmpList for debugging purposes
        for ele := tmpList.Front(); ele != nil; ele = ele.Next() {
            fmt.Printf("creating new list element: %v
    ", ele.Value)
        }
    
        // replace l.mylist with tmpList
        l.mylist = *tmpList
        // another version of this solution could be to return a new (i.e. copied) 
        // *listHolder with all the old values and the new 'text' value
    }
    
    func (l *listHolder) printAll() {
        for temp := l.mylist.Front(); temp != nil; temp = temp.Next() {
            fmt.Println(temp.Value)
        }
    }
    
    func main() {
        a := newListHolder(1)
        a.pushBack("first")  // push a value to a
        a.pushBack("second") // push another value to a
        fmt.Printf("listHolder %d length %d Front()=%v, Back()=%v
    ",
            a.id, a.mylist.Len(), a.mylist.Front().Value, a.mylist.Back().Value)
        a.printAll()
    }
    

    This code outputs:

    creating new list element: first                         // nothing to copy, only creating a new list element
    pushing back 'first' from old list                       // copy element ...
    creating new list element: first                         // ... from old list
    creating new list element: second                        // and push new element to 'tmpList'
    listHolder 1 length 2 Front()=first, Back()=second       // print a summary
    first                                                    // of the
    second                                                   // new list
    

    If I had some mock data, I could do some more testing/debugging. At least this code works without a *list.List.

    评论

报告相同问题?

悬赏问题

  • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计
  • ¥15 帮我写一个c++工程
  • ¥30 Eclipse官网打不开,官网首页进不去,显示无法访问此页面,求解决方法
  • ¥15 关于smbclient 库的使用
  • ¥15 微信小程序协议怎么写
  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教