dst2017 2018-07-10 11:44
浏览 113
已采纳

Go中的“值语义”和“指针语义”是什么意思?

What is the meaning of Value semantics and Pointer semantics in Go? In this course, the author used to mention many times about above terms when explaining internals of arrays and slices which I couldn't understand it completely.

  • 写回答

1条回答 默认 最新

  • duanqian2368 2018-07-10 12:17
    关注

    When you call a function or a method and you pass parameters to it, a copy is made from the values, and the function can only access these copies.

    This means if the function attempts to modify / change the copies, it will not change the original value.

    For example:

    func main() {
        i := 1
        fmt.Println("double:", double(i))
        fmt.Println("original i:", i)
    }
    
    func double(i int) int {
        i *= 2
        return i
    }
    

    This outputs (try it on the Go Playground):

    double: 2
    original i: 1
    

    Even though double() modifies its i parameter, the variable (whose value was passed) at the caller did not change.

    For it to change, we would need to change the signature to expect a pointer, pass a pointer, and modify the pointed value:

    func main() {
        i := 1
        fmt.Println("double:", doublep(&i))
        fmt.Println("original i:", i)
    }
    
    func doublep(i *int) int {
        *i *= 2
        return *i
    }
    

    This outputs (try it on the Go Playground):

    double: 2
    original i: 2
    

    So if we pass something, we're expecting the original value not to change if the passed value is modified, unless we pass a pointer to it.

    Pointer semantics means that even though we pass something "by value", the callee can still modify the "original" value, just as if we would have passed a pointer to it.

    For example:

    func main() {
        is := []int{1, 2}
        fmt.Println("double:", doubles(is))
        fmt.Println("original is:", is)
    }
    
    func doubles(is []int) []int {
        for i := range is {
            is[i] *= 2
        }
        return is
    }
    

    This outputs (try it on the Go Playground):

    double: [2 4]
    original is: [2 4]
    

    Even though we did not pass a pointer (is is not a pointer), the calle modified its elements, and the value of the original slice also changed.

    We say that even though in Go everything is passed by value, passing slices have pointer semantics, because if the callee modifies the elements, it will be reflected in the original.

    Reasoning

    Everything in Go is passed by value, slices too. But slices are–under the hood–struct-like data structures that hold a pointer to an underlying array that holds the actual elements. And when you pass a slice, a copy is made, but only this slice header will be copied (this is the slice value). The copy will hold the same pointer, pointing to the same backing array. The backing array is not copied. So when the callee modifies the elements of the slice, the elements of the backing array are modified, which is the same as the backing array of the original slice.

    Read more about it here: Are golang slices pass by value?

    There are many types that have pass by pointer semantics, such as slices, maps, channels.

    It is worth noting that–unlike slices–arrays are not in the line, an array value means all its values, and passing an array makes a copy of all its elements.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 DIFY API Endpoint 问题。
  • ¥20 sub地址DHCP问题
  • ¥15 delta降尺度计算的一些细节,有偿
  • ¥15 Arduino红外遥控代码有问题
  • ¥15 数值计算离散正交多项式
  • ¥30 数值计算均差系数编程
  • ¥15 redis-full-check比较 两个集群的数据出错
  • ¥15 Matlab编程问题
  • ¥15 训练的多模态特征融合模型准确度很低怎么办
  • ¥15 kylin启动报错log4j类冲突