Недавно начал изучать язык программирования Golang, не очень по началу хотелось, но по работе нужно было, после программирования на Java чуток сложновато. Появилось пару вопросов, в языке Golang простые типы передаются по значению, так же к простому типу относятся и массивы, maps и slices передаются по ссылке, структуры я понял можно передавать как по ссылке так и по значению, все зависит от разработчика, но часто натыкаюсь на примеры в нете где слайсы и мапы передают через взятие адреса, зачем это нужно, если по умолчанию, они все равно так и возвращаются, тем более если передать слайс явно по ссылке то его уже нельзя итерировать, если я что-то не правильно понял объясните, очень мало документации на русском.
Ответ
В golang нет передачи параметров по ссылке - параметры всегда передаются по значению, т.е. копируются. Оператор & - это взятие адреса переменной, т.е. передача указателя, а не передача параметра по ссылке, т.е. как частный случай по значению передаются указатели. map, slice - тоже передаются по значению, просто у них внутри указатели и происходит копирование указателей, а не содержимого таблицы/среза.
Проще всего это продемонстрировать на примере slice (среза). Внутри slice представляет собот структуру:
https://github.com/golang/go/blob/master/src/runtime/slice.go
type slice struct {
array unsafe.Pointer
len int
cap int
}
т.е. при передаче по значению - можно изменять элементы внутри slice.array, т.к. указатель после копирования будет указывать на ту же область памяти что и исходный, но вот изменить длину или вместимость срезу уже не получится. Точнее эти изменения не будут видны снаружи вызываемой функции, т.к. длина, вместимость и (возможно) указатель array изменятся только в копии среза.
Вот наглядный пример:
https://play.golang.org/p/SpFFDdzeXR
package main
import (
"fmt"
)
func f_slice_item(s []int) {
s[0] = 1
}
func f_slice_size(s []int) {
s = append(s, 1)
}
func f_slice_pointer_item(s *[]int) {
(*s)[0] = 3
}
func f_slice_pointer_size(s *[]int) {
*s = append(*s, 5)
}
func f_iter(s *[]int) {
for i, v := range *s {
fmt.Println(i, "-", v)
}
}
func main() {
var s []int
fmt.Println("slice by value")
s = []int{0}
f_slice_item(s)
fmt.Println(s)
s = []int{0}
f_slice_size(s)
fmt.Println(s)
fmt.Println()
fmt.Println("slice by pointer")
s = []int{0}
f_slice_pointer_item(&s)
fmt.Println(s)
s = []int{0}
f_slice_pointer_size(&s)
fmt.Println(s)
fmt.Println()
fmt.Println("iter")
f_iter(&s)
}
Результат выполнения:
slice by value
[1]
[0]
slice by pointer
[3]
[0 5]
iter
0 - 0
1 - 5
Комментариев нет:
Отправить комментарий