如何用指针修改切片?为何示例代码中切片未被修改?
问题解答
为什么你的切片元素没被修改?
咱们先揪出modifyArray函数里的关键问题:
for _, v := range *vertices { v.x = v.x * v.x v.y = v.y * v.y }
这里的v是切片中每个Vertex元素的值副本——每次循环都会把切片里的元素完整复制一份到临时变量v里,你对v做的所有修改都只作用在这个临时变量上,和原切片里的元素完全没关系!这就是最后打印切片时,元素还是原始值的根本原因。
顺便补充个小细节:切片本身是引用类型,其实你根本不需要传*[]Vertex这种切片指针(除非你要修改切片的长度、容量,比如调用append后想让原切片指向新的底层数组)。你传[]Vertex就足够让函数访问到同一个底层数组,但问题出在遍历方式上,不是传参的问题。
如何用指针正确修改切片?
有两种常用的正确姿势,你可以根据场景选择:
1. 通过索引直接操作原切片元素
既然range返回的是副本,那咱们就绕开副本,直接通过索引访问原切片里的元素:
func modifyArray(vertices []Vertex) { // 不用传指针,切片本身是引用类型 for i := range vertices { // 直接修改切片索引对应的元素,完全没有副本问题 vertices[i].x *= vertices[i].x vertices[i].y *= vertices[i].y } } // 调用时直接传切片即可 modifyArray(vertices)
2. 将切片元素改为指针类型
如果你的业务场景更适合用指针,那可以把切片的元素类型改成*Vertex,这样range返回的指针副本指向的还是原对象,修改自然会生效:
func modifyArray(vertices []*Vertex) { for _, v := range vertices { // v是指针,修改的是指针指向的原Vertex对象 v.x *= v.x v.y *= v.y } } // 调用时创建指针类型的切片 v1 := &Vertex{2, 3} v2 := &Vertex{20, 30} vertices := []*Vertex{v1, v2} modifyArray(vertices)
总结用指针修改切片的核心要点
- 如果切片元素是值类型:要么通过索引直接修改原元素,要么把元素类型改成指针
- 只有当你需要修改切片本身的结构(比如扩容、缩容,改变切片的len/cap)时,才需要传递切片的指针(
*[]T);单纯修改元素的话,切片本身的引用就足够了
内容的提问来源于stack exchange,提问作者raka
相关产品推荐
相关产品推荐

