Страницы

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

воскресенье, 16 февраля 2020 г.

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

#golang #указатели #типы_данных


Недавно начал изучать язык программирования Golang, не очень по началу хотелось,
но по работе нужно было, после программирования на Java чуток сложновато.
Появилось пару вопросов, в языке Golang простые типы передаются по значению, так
же к простому типу относятся и массивы, maps и slices передаются по ссылке, структуры
я понял можно передавать как по ссылке так и по значению, все зависит от разработчика,
но часто натыкаюсь на примеры в нете где слайсы и мапы передают через взятие адреса,
зачем это нужно, если по умолчанию, они все равно так и возвращаются, тем более если
передать слайс явно по ссылке то его уже нельзя итерировать, если я что-то не правильно
понял объясните, очень мало документации на русском.
    


Ответы

Ответ 1



В 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

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

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