如何使用指针修改切片

时间:2018-04-27 21:32:14

标签: go

为什么不在以下代码中修改切片:

package pointers

import "fmt"

func modifyObject(v *Vertex) {
    v.x = v.x * v.x
    v.y = v.y * v.y
}

func modifyArray(vertices *[]Vertex) {
    for _, v := range *vertices {
        v.x = v.x * v.x
        v.y = v.y * v.y
    }
}

func DemoPointersArray() {
    v := Vertex{2, 3}
    modifyObject(&v)
    fmt.Println("Vertex modified successfully:", v)

    v1 := Vertex{2, 3}
    v2 := Vertex{20, 30}
    vertices := []Vertex{v1, v2}
    modifyArray(&vertices)
    fmt.Println("Vertices are NOT modified:", vertices)
}

输出:
顶点修改成功:{4 9}
顶点不会被修改:[{2 3} {20 30}]

如何修改它们?

2 个答案:

答案 0 :(得分:7)

在第二个示例中,您将指针传递给切片。由于切片已经是指向数组的指针(以及长度和容量),因此几乎没有理由这样做。

enter image description here enter image description here

指向切片的指针包含Vertex的实例,而不是* Vertex,因此修改它们没有任何影响。如果您改为将方法签名更改为

func modifyArray(vertices []*Vertex) 

并传递了一些指针,然后你可以像预期的那样修改它们。

这是一个以playground为例向您展示。相应的代码在

下面
package main

import "fmt"

type Vertex struct {
    x int
    y int
}

func modifyObject(v *Vertex) {
    v.x = v.x * v.x
    v.y = v.y * v.y
}

func modifyArray(vertices []*Vertex) {
    for _, v := range vertices {
        v.x = v.x * v.x
        v.y = v.y * v.y
    }
}

func main() {
    v := Vertex{2, 3}
    modifyObject(&v)
    fmt.Println("Vertex modified successfully:", v)

    v1 := Vertex{2, 3}
    v2 := Vertex{20, 30}
    vertices := []*Vertex{&v1, &v2}
    modifyArray(vertices)
    fmt.Printf("Vertices are modified: %v %v", vertices[0], vertices[1])
}

答案 1 :(得分:3)

函数modifyArray修改局部变量v,而不是切片元素。使用索引表达式分配给slice元素:

func modifyArray(vertices *[]Vertex) {
    for i, v := range *vertices {
        (*vertices)[i].x = v.x * v.x
        (*vertices)[i].y = v.y * v.y
    }
}

因为切片包含指向后备数组的指针,所以不需要将指针传递给切片:

func modifyArray(vertices []Vertex) {
    for i, v := range vertices {
        vertices[i].x = v.x * v.x
        vertices[i].y = v.y * v.y
    }
}

这样称呼:

modifyArray(vertices)  // do not take address of vertices

playground example

您可以通过获取切片元素的地址来使用modifyObject

 func modifyArray(vertices []Vertex) {
    for i := range vertices {
        modifyObject(&vertices[i])
    }
}

playground example

与其他答案不同,此答案会保留问题中的内存布局。