Рубрики
go

013 / go Указатели

Указатели

Оператор & (амперсанд) используется в 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)
}