Указатели
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
Оператор & (амперсанд) используется в 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 | значение, хранящееся по этому адресу! !!! Значения, представляющие адреса переменных, называются указателями, потому что они указывают на область памяти, в которой хранится переменная. |
Типы указателей
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
Тип указателя состоит из знака * и типа переменной, на которую ссылается указатель. Например, тип указателя на переменную 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) } |
Чтение или изменение значения по указателю
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
!!! Оператор * может использоваться для обновления значения по указателю. 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 |
Использование указателей с функциями
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
Указатели также можно возвращать из функций; просто объявите возвращаемый тип функции как тип указателя. Пример кода: 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) } |