请解释golang类型是否按值传递

时间:2017-11-25 13:40:13

标签: go parameter-passing pass-by-reference pass-by-value pass-by-pointer

我正在尝试创建一个非常简单的程序来修改数组,但是如果我将它们转换为类型则会遇到一些有趣的行为。 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 := []int{1, 2, 3}
    c := cT{1, 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
}

2 个答案:

答案 0 :(得分:3)

  

The Go Programming Language Specification

     

Array types

     

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

     

Slice types

     

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

     

Calls

     

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

type cT [3]int

b := []int{1, 2, 3}
c := cT{1, 2, 3}
     

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

不,你不要!

bint切片,其长度为len(b))3,容量为cap(b))3,c是(len(c))3 int

数组

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

答案 1 :(得分:0)

见评论:

 
func main() {
    b := []int{1, 2, 3} // slice
    c := cT{1, 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)
}

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