如何从函数返回切片的更改值?

时间:2017-07-14 03:05:18

标签: go slice

如果这是一个微不足道的问题,我是新来的,请原谅我。我想迭代一段帖子并增加每个帖子 func incrementViews(posts []model.Post) []model.Post { for _, v := range posts { v.Views++ fmt.Println(v.Views) //Views incremented by 1 } return posts } incrementViews(posts) //Views not changed 的值:

incrementViews(posts)

打印值已更改,但当我调用*时,返回的值不变。

我尝试使用&的{​​{1}}来解决这个问题,但可能无法做到这一点,因为我来自Python背景,并且已经忘记了通过指针和值移动变量。

2 个答案:

答案 0 :(得分:1)

问题中的代码是更新局部变量v。将切片更改为* model.Post或使用索引运算符更新切片中的值。前者需要更改呼叫者。

func incrementViews(posts []*model.Post) []*model.Post {
    for _, v := range posts { 
        v.Views++
    }
    return posts
}

func incrementViews(posts []model.Post) []model.Post {
    for i := range posts { 
        posts[i].Views++
    }
    return posts
}

修改

这两种方法都有效,请参见此处:https://play.golang.org/p/90BNOFYaKL

答案 1 :(得分:1)

range表达式返回slice元素的副本。因此,在迭代时想要修改切片元素时应该非常小心。

切片或数组上的range表达式将第一个参数作为索引返回,将第二个参数作为该索引处元素的副本返回。在您的示例中,您正在修改范围返回的副本,因此无法在原始切片元素中进行修改。

您需要更改的是,使用[索引]引用切片名称,以便实际引用切片中的原始元素,从而可以修改原始切片元素。请参阅jeevatkm给出的工作示例中的second approach

另一个选项是使用切片地址,在这种情况下,您可以引用范围返回的值,因为即使它是副本,它也是地址位置的副本,它仍然指向原始元素。请参阅jeevatkm给出的工作示例中的第一种方法。