Пожалуйста, объясните, передаются ли типы Голанга по значению

Я пытаюсь сделать очень простую программу, которая модифицирует массивы, но натолкнулась на интересное поведение, если я преобразовала их в типы. https://play.golang.org/p/KC7mqmHuLw Похоже, что если у меня есть массив, go проходит по ссылке, но если у меня есть тип, то go проходит по значению. Это правильно?

У меня есть две переменные b и c, обе являются массивами из 3 целых чисел, но c имеет тип cT, во всех остальных отношениях они должны быть идентичными. Я могу назначить значения как b[0]=-1 а также c[0]=-1, но если я передам эти массивы как параметры функции, они будут действовать по-разному.

Выход программы:

до б: [1 2 3]

до с: [1 2 3]

* после б: [-1 2 0]

* после c: [-1 2 3]

*какие? с: [-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 ответа

Решение

Спецификация языка программирования Go

Типы массивов

Массив - это пронумерованная последовательность элементов одного типа, называемая типом элемента.

Типы срезов

Срез является дескриптором для непрерывного сегмента базового массива и обеспечивает доступ к пронумерованной последовательности элементов из этого массива.

Вызовы

При вызове функции значение и аргументы функции оцениваются в обычном порядке. После того, как они оценены, параметры вызова передаются функции по значению и вызываемая функция начинает выполнение. Возвращаемые параметры функции передаются по значению обратно в вызывающую функцию, когда функция возвращается.


type cT [3]int

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

У меня есть две переменные, b а также cоба являются массивами из 3 целых чисел


Нет!

b кусочек int с длиной (len(b)) 3 и вместимость (cap(b)) 3, c это массив (len(c)) 3 int,

В Go все параметры передаются по значению. b передается как дескриптор среза, c передается как массив. Дескриптор среза является struct с длиной и емкостью среза и указателем на базовый массив.

Смотрите комментарии:

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

Другие вопросы по тегам