Страницы

Поиск по вопросам

понедельник, 8 июля 2019 г.

Вопрос по указателям в Golang

Недавно начал изучать язык программирования 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

Комментариев нет:

Отправить комментарий