Search code examples
goparameter-passingpass-by-referencepass-by-valuepass-by-pointer

Please explain if golang types pass by value


I'm trying to make a very simple program that modifies arrays, but ran across some interesting behavior if I converted them to types. https://play.golang.org/p/KC7mqmHuLw It appears that if I have an array go passes by reference, but if I have a type then go passes by value. Is this correct?

I have two variables b and c, both are arrays of 3 integers, but c is of type cT, in every other respect they should be identical. I can assign values as b[0]=-1 and c[0]=-1, but if I pass those arrays as parameters to a function they act very differently.

The output of the program is:

before b: [1 2 3]

before c: [1 2 3]

*after b: [-1 2 0]

*after c: [-1 2 3]

*what? c: [-1 2 0]

My initial assumption is that the lines "after b" and "after c" should have been the same. Am I doing something incorrectly or am I correct about types passing to functions by value (ie. creating copy of the variable before passing to the function)?

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
}

Solution

  • The Go Programming Language Specification

    Array types

    An array is a numbered sequence of elements of a single type, called the element type.

    Slice types

    A slice is a descriptor for a contiguous segment of an underlying array and provides access to a numbered sequence of elements from that array.

    Calls

    In a function call, the function value and arguments are evaluated in the usual order. After they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution. The return parameters of the function are passed by value back to the calling function when the function returns.


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

    I have two variables, b and c, both are arrays of 3 integers


    No, you don't!

    b is a slice of int with length (len(b)) 3 and capacity (cap(b)) 3, c is an array of (len(c)) 3 int.

    In Go, all parameters are passed by value. b is passed as a slice descriptor, c is passed as an array. A slice descriptor is a struct with a slice length and capacity, and a pointer to the underlying array.