一尘不染

删除结构中切片的元素

go

我有一个结构“ Guest”,其中包含聚会客人的元数据(唯一的ID,名称,姓氏以及作为该客人的朋友的客人的唯一ID的列表。

type Guest struct {
    id      int
    name    string
    surname string
    friends []int
}

我有以下代码从朋友列表中删除ID:

func (self Guest) removeFriend(id int) {
    for i, other := range self.friends {
        if other == id {
            self.friends = append(self.friends[:i], self.friends[i+1:]...)
            break
        }
    }
}

问题是:我要删除的元素被元素的移位覆盖,但是切片不会变短。而是将切片的最后一个元素相乘。

举一个例子:guest1.friends[1,2,3,4,5]。我打电话后guest1.removeFriend(3),结果[1,2,4,5,5]却不是理想的[1,2,4,5]

那么,我在做什么错呢?


阅读 210

收藏
2020-07-02

共1个答案

一尘不染

任何打算/确实修改接收器的方法都必须使用指针接收器。

您的Guest.removeFriend()方法确实尝试修改接收器(类型Guest),即其friends字段(属于切片类型),但是由于您仅使用了值接收器,因此您仅在修改副本的friends字段Guest。原始Guest值将具有未修改的切片值。

因此,您 必须 使用指针接收器:

func (self *Guest) removeFriend(id int) {
    // ...
}

测试它:

g := &Guest{
    id:      1,
    name:    "Bob",
    surname: "Pats",
    friends: []int{1, 2, 3, 4, 5},
}

fmt.Println(g)
g.removeFriend(3)
fmt.Println(g)

输出(在Go Playground上尝试):

&{1 Bob Pats [1 2 3 4 5]}
&{1 Bob Pats [1 2 4 5]}

关于在您的版本中看到的内容的说明,切片是指向实际包含元素的数组的小型结构描述符。在您的示例中,您修改了backing数组的元素,因此具有原始切片的调用方将看到这些修改,但是原始切片的大小不会(无法)改变。

通过使用指针接收器,您会将新的切片值(由返回append())分配给friends原始字段Guest,切片值的长度将减小1(由于删除了1个元素)。

另外请注意,在Go中使用诸如self和的接收者名称this不是惯用语,而是可以使用guestg

2020-07-02