Пожалуйста, объясните, передаются ли типы Голанга по значению
Я пытаюсь сделать очень простую программу, которая модифицирует массивы, но натолкнулась на интересное поведение, если я преобразовала их в типы. 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://blog.golang.org/go-slices-usage-and-internals