Указатели
Оператор & (амперсанд) используется в Go для получения адреса переменной.
Например, следующий код инициализирует переменную, сначала выводит ее значение, а затем адрес переменной...
Пример кода:
package main
import "fmt"
func main() {
amount := 6
fmt.Println(amount) //Выводит значение переменной
fmt.Println(&amount) //Выводит адрес переменной
}
вывод кода:
6 //Значение переменной.
0x400011c010 //Адрес переменной.
Адрес можно получить для переменной любого типа.
Обратите внимание, все переменные имеют разные адреса.
Еще пример кода:
package main
import "fmt"
func main() {
var myInt int
fmt.Println(&myInt)
var myFloat float64
fmt.Println(&myFloat)
var myBool bool
fmt.Println(&myBool)
}
Вывод кода:
0x40000ba010
0x40000ba018
0x40000ba030
И что же собой представляют эти «адреса»?
Чтобы найти конкретный дом в плотно застроенном городе, вам нужно знать его адрес...
Память, выделяемая компьютером программе, так же переполнена, как и городские улицы.
Она забита значениями переменных: логическими значениями, целыми числами, строками и т. д.
Зная адрес переменной, вы сможете воспользоваться им для получения значения, хранящегося в переменной.
Адрес
|
0x1040a100 0x1040a108 0x1040a110 0x1040a118 0x1040a120 0x1040a128
true 6 ... ... ... 3.1415
|
значение, хранящееся по этому адресу!
!!! Значения, представляющие адреса переменных, называются указателями, потому что они указывают на область памяти, в которой хранится переменная.
Типы указателей
Тип указателя состоит из знака * и типа переменной, на которую ссылается указатель.
Например, тип указателя на переменную int записывается в виде *int (читается «указатель на int»).
С помощью функции reflect.TypeOf можно вывести типы указателей из приведенной ранее программы:
package main
import (
"fmt"
"reflect"
)
func main() {
var myInt int
fmt.Println(reflect.TypeOf(&myInt)) //Получает указатель на myInt и выводит тип указателя.
var myFloat float64
fmt.Println(reflect.TypeOf(&myFloat)) //Получает указатель на myFloat и выводит тип указателя.
var myBool bool
fmt.Println(reflect.TypeOf(&myBool)) //Получает указатель на myBool и выводит тип указателя.*
}
В программе можно объявлять переменные, содержащие указатели.
В таких переменных могут храниться только указатели на один конкретный тип переменной,
так что переменная может содержать только указатели *int, только указатели *float64 и т. д.
package main
import "fmt"
func main() {
myInt := 4 //Значение
myIntPointer := &myInt //Указатель
fmt.Println(myIntPointer) //Выводится сам указатель.
fmt.Println(*myIntPointer) //Выводится значение, на которое ссылается указатель.
myFloat := 98.6 //Значение
myFloatPointer := &myFloat //Указатель
fmt.Println(myFloatPointer) //Выводит сам указатель
fmt.Println(*myFloatPointer) //Выводится значение, на которое ссылается указатель.
myBool := true //Значение
myBoolPointer := &myBool ////Указатель
fmt.Println(myBoolPointer) //Выводит сам указатель
fmt.Println(*myBoolPointer) //Выводится значение, на которое ссылается указатель.
Как и с другими типами, при немедленном присваивании исходного значения переменной-указателю можно воспользоваться коротким объявлением переменной.
package main
import "fmt"
func main() {
var myBool bool
myBoolPointer := &myBool //Короткое объявление переменной-указателя.
fmt.Println(myBoolPointer)
}
Чтение или изменение значения по указателю
!!! Оператор * может использоваться для обновления значения по указателю.
package main
import "fmt"
func main() {
myInt := 4 //Значение
fmt.Println(myInt) //Вывести значение
myIntPointer := &myInt //Создаем указатель
*myIntPointer = 8 //Новое значение присваивается переменной, на которую ссылается указатель (myInt).
fmt.Println(*myIntPointer) //Выводится значение переменной, на которую ссылается указатель.
fmt.Println(myInt) //Значение переменной выводится напрямую.
}
/*
4 Исходное значение myInt.
8 Результат обновления *myIntPointer.
8 Обновление значения myInt (то же, что *myIntPointer).
*/
В приведенном коде команда *myIntPointer = 8 обращается к переменной,
на которую ссылается указатель myIntPointer (то есть переменной myInt) и присваивает ей новое значение.
Таким образом, обновляется не только значение *myIntPointer, но и myInt
Использование указателей с функциями
Указатели также можно возвращать из функций;
просто объявите возвращаемый тип функции как тип указателя.
Пример кода:
package main
import "fmt"
func createInt() *int {
var myInt = 100
return &myInt
}
func createPointer() *float64 {
var myFloat = 98.5
return &myFloat
}
func crS() *string {
var xX = "hello all"
return &xX
}
func main() {
var myFloatPointer *float64 = createPointer()
fmt.Println(*myFloatPointer)
var x *int = createInt()
fmt.Println(*x)
var x1 *string = crS()
fmt.Println(*x1)
}
Кстати говоря, в отличие от некоторых других языков, в Go можно вернуть указатель на переменную, локальную по отношению к функции.
И хотя эта переменная уже не находится в области видимости, пока у вас есть указатель, Go предоставит вам доступ к значению этой переменной.
package main
import "fmt"
func printPointer(myBoolPointer *bool) {
fmt.Println(*myBoolPointer)
}
func main() {
var myBool bool = true
printPointer(&myBool)
}