10

围棋又难倒了我。希望有人可以提供帮助。我创建了一个切片 (mySlice),其中包含指向结构 (myStruct) 的指针。

问题是“删除”方法。当我们在“Remove”里面时一切都很好,但是一旦我们返回,切片大小并没有改变,所以我们看到最后一个元素列出了两次。

我最初尝试使用“添加”方法中使用的相同模式编写“删除”,但它不会编译并且已被注释掉。

我可以通过将新创建的切片返回给调用函数来使其工作,但我不想这样做,因为 mySlice (ms) 是一个单例。

如果我还没有问够...

“添加”方法的代码正在运行,尽管我不确定如何。据我所知,“添加”正在接收指向切片标头(第 3 项“结构”)的指针。根据我的阅读,切片的长度和容量不会传递给方法(当按值传递时),所以也许将指针传递给切片允许方法查看和使用长度和容量,从而允许我们“附加”。如果这是真的,那么为什么相同的模式在“删除”中不起作用?

非常感谢大家的见解和帮助!

package main

import (
    "fmt"
)

type myStruct struct {
    a int
}
type mySlice []*myStruct

func (slc *mySlice) Add(str *myStruct) {
    *slc = append(*slc, str)
}

//does not compile with reason: cannot slice slc (type *mySlice)
//func (slc *mySlice) Remove1(item int) {
//  *slc = append(*slc[:item], *slc[item+1:]...)
//}

func (slc mySlice) Remove(item int) {
    slc = append(slc[:item], slc[item+1:]...)
    fmt.Printf("Inside Remove = %s\n", slc)
}

func main() {
    ms := make(mySlice, 0)
    ms.Add(&myStruct{0})
    ms.Add(&myStruct{1})
    ms.Add(&myStruct{2})
    fmt.Printf("Before Remove:  Len=%d, Cap=%d, Data=%s\n", len(ms), cap(ms), ms)
    ms.Remove(1) //remove element 1 (which also has a value of 1)
    fmt.Printf("After Remove:  Len=%d, Cap=%d, Data=%s\n", len(ms), cap(ms), ms)
}

和结果...

Before Remove:  Len=3, Cap=4, Data=[%!s(*main.myStruct=&{0}) %!s(*main.myStruct=&{1}) %!s(*main.myStruct=&{2})]

Inside Remove = [%!s(*main.myStruct=&{0}) %!s(*main.myStruct=&{2})]

After Remove:  Len=3, Cap=4, Data=[%!s(*main.myStruct=&{0}) %!s(*main.myStruct=&{2}) %!s(*main.myStruct=&{2})]
4

2 回答 2

14

你第一次是对的Remove1()。Remove 获取切片的副本,因此无法更改切片的长度。

您的删除功能中的问题是,根据 Go 中的操作顺序,切片先于取消引用。

解决方法是更改*slc = append(*slc[:item], *slc[item+1:]...)​​为*slc = append((*slc)[:item], (*slc)[item+1:]...).

但是,为了可读性和可维护性,我建议以下内容:

func (slc *mySlice) Remove1(item int) {
    s := *slc
    s = append(s[:item], s[item+1:]...)
    *slc = s
}
于 2013-09-02T06:07:18.650 回答
1

因为正如 Stephen Weinberg 所指出的, append不一定会返回对切片的相同引用地址。解决此限制的另一种方法是定义一个包装切片的结构。

例如:

package main

import "fmt"

type IntList struct {
    intlist []int
}

func (il *IntList) Pop() {
    if len(il.intlist) == 0 { return }
    il.intlist = il.intlist[:len(il.intlist)-1]
}

func (il *IntList) Add(i... int) {
    il.intlist = append(il.intlist, i...)
}

func (il *IntList) String() string {
    return fmt.Sprintf("%#v",il.intlist)
}

func main() {
    intlist := &IntList{[]int{1,2,3}} 
    fmt.Println(intlist)
    intlist.Pop()
    fmt.Println(intlist)
    intlist.Add([]int{4,5,6}...)
    fmt.Println(intlist)
}

输出:

[]int{1, 2, 3}
[]int{1, 2}
[]int{1, 2, 4, 5, 6}
于 2014-02-22T15:32:50.903 回答