请说明golang类型是不是按值传递

Posted

技术标签:

【中文标题】请说明golang类型是不是按值传递【英文标题】:Please explain if golang types pass by value请说明golang类型是否按值传递 【发布时间】:2018-05-09 06:08:18 【问题描述】:

我正在尝试制作一个非常简单的程序来修改数组,但是如果我将它们转换为类型,则会遇到一些有趣的行为。 https://play.golang.org/p/KC7mqmHuLw 看来,如果我有一个数组,则按引用传递,但如果我有一个类型,则按值传递。这是正确的吗?

我有两个变量 b 和 c,都是 3 个整数的数组,但 c 是 cT 类型,在其他方面它们应该是相同的。我可以将值分配为b[0]=-1c[0]=-1,但如果我将这些数组作为参数传递给函数,它们的行为就会大不相同。

程序的输出是:

在 b 之前:[1 2 3]

在 c 之前:[1 2 3]

*在 b 之后:[-1 2 0]

*在 c 之后:[-1 2 3]

*什么? c: [-1 2 0]

我最初的假设是“b 之后”和“c 之后”的行应该是相同的。我做错了什么还是我对按值传递给函数的类型是否正确(即在传递给函数之前创建变量的副本)?

package main

import "fmt"

type cT [3]int

func main() 
    b := []int1, 2, 3
    c := cT1, 2, 3

    fmt.Println("before b:", b)
    fmt.Println("before c:", c)

    b[0] = -1
    c[0] = -1
    mangleB(b) // ignore return value
    mangleC(c) // ignore return value

    fmt.Println("*after b:", b)
    fmt.Println("*after c:", c)

    c = mangleC(c)    
    fmt.Println("*what? c:", c)    


func mangleB(row []int) []int 
    row[2] = 0
    return row


func mangleC(row cT) cT
    row[2] = 0
    return row

【问题讨论】:

好的,感谢您的帮助!根据提供的信息,我通过传递对类型 manglePC(&c) 的引用并将函数更改为:func manglePC(row *cT) (*row)[2] = 0 来获得我想要的效果 【参考方案1】:

The Go Programming Language Specification

Array types

数组是单一类型的元素的编号序列,称为 元素类型。

Slice types

切片是底层的连续段的描述符 数组并提供对该数组元素的编号序列的访问 数组。

Calls

在函数调用中,函数值和参数在 通常的顺序。在评估它们之后,调用的参数 通过值传递给函数并且被调用的函数开始 执行。函数的返回参数按值传递 函数返回时返回调用函数。


type cT [3]int

b := []int1, 2, 3
c := cT1, 2, 3

我有两个变量,bc,都是 3 个整数的数组


不,你没有!

bintslice,长度 (len(b)) 3 和容量 (cap(b)) 3,c数组 (len(c)) 3 int

在 Go 中,所有参数都是按值传递的。 b 作为切片描述符传递,c 作为数组传递。切片描述符是一个struct,具有切片长度和容量,以及指向底层数组的指针。

【讨论】:

【参考方案2】:

见 cmets:

func main() 
    b := []int1, 2, 3 // slice
    c := cT1, 2, 3 // array

    fmt.Println("before b:", b) 
    fmt.Println("before c:", c) 

    b[0] = -1
    c[0] = -1

    // passing in a slice which you can think of as ref to array
    // pass by value, and it is copy of ref to array 
    mangleB(b) // ignore return value

    // passing in copy of array (pass by value)
    // yes full shallow copy of array 
    mangleC(c) // ignore return value
    // if you ignore return modifications are lost

    fmt.Println("*after b:", b)
    fmt.Println("*after c:", c)

    // return value is modified array
    c = mangleC(c)
    // c now copy of array from line 24

    fmt.Println("*what? c:", c)

当我将 slice 称为 ref 时,我在这里简化了细节https://blog.golang.org/go-slices-usage-and-internals

https://play.golang.org/p/OAaCMhc-Ug

【讨论】:

以上是关于请说明golang类型是不是按值传递的主要内容,如果未能解决你的问题,请参考以下文章

我应该在哪里更喜欢按引用传递或按值传递?

按值传递/指针/引用说明

java中参数传递--值传递,引用传递

js按值传递还是按引用传递?

java中的参数传递——值传递引用传递

切片是按值传递的吗?