doudou3213 2016-05-21 18:33
浏览 44
已采纳

将struct属性(切片)传递给从中删除元素的函数时的奇怪行为

I've started learning Go these days and got stuck in trying to pass a struct property's value (a slice) to a function. Apparently it's being passed as a reference (or it holds a pointer to its slice) and changes made inside the function affect it.

Here is my code, in which testFunction is supposed to receive a slice, remove its first 3 elements and print the updated values, but without affecting it externally:

package main

import (
    "fmt"
)

type testStruct struct {
    testArray []float64
}

var test = testStruct {
    testArray: []float64{10,20,30,40,50},
}

func main() {
    fmt.Println(test.testArray)
    testFunction(test.testArray)
    fmt.Println(test.testArray)
}

func testFunction(array []float64) {
    for i:=0; i<3; i++ {
        array = removeFrom(array, 0)
    }
    fmt.Println(array)
}

func removeFrom(array []float64, index int) []float64 {
    return append(array[:index], array[index+1:]...)
}

That outputs:

[10 20 30 40 50]
[40 50]
[40 50 50 50 50]

My question is: what is causing the third fmt.Println to print this strange result?

Playground: https://play.golang.org/p/G8W3H085In

p.s.: This code is only an example. It's not my goal to remove the first elements of something. I just wanna know what is causing this strange behaviour.

  • 写回答

3条回答 默认 最新

  • duanqiao1926 2016-05-21 18:57
    关注

    Usually we don't know whether a given call to append will cause a reallocation, so we can't assume that the original slice refers to the same array as the resulting slice, nor that it refers to a different one.

    To use slices correctly, it's important to remember that although the elements of the underlying array are indirect, the slice's pointer, length and capacity are not.

    As a result, it's usual to assign the result of a call to append to the same slice variable:

    array = append(array, ...)
    

    So to sum up, to receive the desired result always remember to assign the append function to a new or the same slice variable.

    Here is the corrected and working code:

    package main
    
    import (
        "fmt"
    )
    
    type testStruct struct {
        testArray []float64
    }
    
    var test = testStruct {
        testArray: []float64{10,20,30,40,50},
    }
    
    func main() {
        fmt.Println(test.testArray)
        a := testFunction(test.testArray)
        fmt.Println(a)
    }
    
    func testFunction(array []float64)[]float64 {
        for i:=0; i<3; i++ {
            array = removeFrom(array, 0)
        }
        fmt.Println(array)
        return array
    }
    
    func removeFrom(array []float64, index int) []float64 {
        return append(array[:index], array[index+1:]...)
    }
    

    Check it the working code on <kbd>Go Playground</kbd>.


    Another solution is to pass the array argument via pointer reference:

    func testFunction(array *[]float64) {
        for i:=0; i<3; i++ {
            *array = removeFrom(*array, 0)
        }
        fmt.Println(*array)
    }
    

    <kbd>Go Playground</kbd>

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图
  • ¥15 关于大棚监测的pcb板设计
  • ¥15 stm32开发clion时遇到的编译问题
  • ¥15 lna设计 源简并电感型共源放大器
  • ¥15 如何用Labview在myRIO上做LCD显示?(语言-开发语言)
  • ¥15 Vue3地图和异步函数使用