Указатели на GO
#GOУказатели на языке программирования Go или Golang — это переменная, которая используется для хранения адреса памяти другой переменной. Указатели на Голанг также называются специальными переменными. Переменные используются для хранения некоторых данных по определенному адресу памяти в системе. Адрес памяти всегда находится в шестнадцатеричном формате.
Какая потребность в указателях?
Чтобы понять эту потребность, во-первых, мы должны понять концепцию переменных. Переменные — это имена, данные в ячейке памяти, где хранятся фактические данные. Для доступа к хранимым данным нам нужен адрес этой конкретной ячейки памяти. Запоминать все адреса памяти (шестнадцатеричный формат) вручную — непростая задача, поэтому мы используем переменные для хранения данных, и к переменным можно обращаться, просто используя их имя.
Golang также позволяет сохранять шестнадцатеричное число в переменной, используя буквальное выражение, то есть число, начинающееся с 0x, является шестнадцатеричным числом.
Пример: в приведенной ниже программе мы сохраняем шестнадцатеричное число в переменной. Но вы можете видеть, что тип значений int и сохраняется как десятичное число, или вы можете сказать, что десятичное значение типа int хранит. Но основной смысл объяснения этого примера заключается в том, что мы храним шестнадцатеричное значение (считайте его адресом памяти), но это не указатель, поскольку он не указывает на какое-либо другое место в памяти другой переменной. Это просто пользовательская переменная. Так что возникает необходимость в указателях.
// Программа Голанг для демонстрации переменных
// сохраняем шестнадцатеричные значения
package main
import "fmt"
func main() {
// сохраняем шестнадцатеричное
// значения в переменных
x := 0xFF
y := 0x9C
// Отображение значений
fmt.Printf("Type of variable x is %T\n", x)
fmt.Printf("Value of x in hexdecimal is %X\n", x)
fmt.Printf("Value of x in decimal is %v\n", x)
fmt.Printf("Type of variable y is %T\n", y)
fmt.Printf("Value of y in hexdecimal is %X\n", y)
fmt.Printf("Value of y in decimal is %v\n", y)
}
Выход:
Type of variable x is int Value of x in hexdecimal is FF Value of x in decimal is 255 Type of variable y is int Value of y in hexdecimal is 9C Value of y in decimal is 156
Указатель — это особая переменная, которая используется не только для хранения адресов памяти других переменных, но также указывает, где находится память, и предоставляет способы для определения значения, хранящегося в этой ячейке памяти. Обычно он называется «Специальный тип переменной», потому что он почти объявлен как переменная, но с * (оператор разыменования).

Декларация и инициализация указателей
Прежде чем мы начнем, есть два важных оператора, которые мы будем использовать в указателях.
Оператор также называется оператором разыменования, используемым для объявления переменной указателя и доступа к значению, сохраненному в адресе.
Оператор & называется оператором адреса, который используется для возврата адреса переменной или для доступа к адресу переменной для указателя.
Объявление указателя :
var pointer_name *Data_Type
Пример: ниже указатель типа string, который может хранить только адреса памяти строковых переменных.
var s *string
Инициализация указателя: для этого вам нужно инициализировать указатель с адресом памяти другой переменной, используя оператор адреса, как показано в следующем примере:
// normal variable declaration var a = 45 // Initialization of pointer s with // memory address of variable a var s *int = &a
Пример:
// Программа Голанг для демонстрации декларации
// и инициализация указателей
package main
import "fmt"
func main() {
// берём нормальную переменную
var x int = 5748
// объявление указателя
var p *int
// инициализация указателя
p = &x
// отображение результата
fmt.Println("Value stored in x = ", x)
fmt.Println("Address of x = ", &x)
fmt.Println("Value stored in variable p = ", p)
}
Выход:
Value stored in x = 5748 Address of x = 0x414020 Value stored in variable p = 0x414020
Важные моменты:
- Значение по умолчанию или нулевое значение указателя всегда равно нулю . Или вы можете сказать, что неинициализированный указатель всегда будет иметь значение nil.
Пример:
// Программа Голанг для демонстрации// нулевое значение указателяpackage mainimport "fmt"func main() {// берём указательvars *int// отображение результатаfmt.Println("s = ", s)}- Выход:
s = <nil>
- Объявление и инициализация указателей может быть сделано в одну строку.
Пример:
var s *int = &a
- Если вы указываете тип данных вместе с объявлением указателя, то указатель сможет обработать адрес памяти этой указанной переменной типа данных. Например, если вы берете указатель строкового типа, то адрес переменной, которую вы дадите указателю, будет только строковой переменной типа данных, а не любого другого типа.
- Чтобы преодолеть вышеуказанную проблему, вы можете использовать концепцию определения типа ключевого слова var . Нет необходимости указывать тип данных во время объявления. Тип переменной-указателя также может быть определен компилятором как обычная переменная. Здесь мы не будем использовать оператор *. Он будет внутренне определяться компилятором, когда мы инициализируем переменную с адресом другой переменной.Пример:
// Программа Голанг для демонстрации// использование вывода типа в// переменные указателяpackage mainimport "fmt"func main() {// используя ключевое слово var// мы не определяем// любой тип с переменнойvary = 458// берём указатель на переменную используя// ключевое слово var без указания// типvarp = &yfmt.Println("Value stored in y = ", y)fmt.Println("Address of y = ", &y)fmt.Println("Value stored in pointer variable p = ", p)}- Выход:
Value stored in y = 458 Address of y = 0x414020 Value stored in pointer variable p = 0x414020
- Вы также можете использовать сокращенный синтаксис (: =) для объявления и инициализации переменных-указателей. Компилятор сам определит, что переменная является переменной-указателем, если мы передаем адрес переменной с помощью оператора & (address) .Пример:
// Программа Голанг для демонстрации// использование сокращенного синтаксиса в// переменные указателяpackage mainimport "fmt"func main() {// используя оператор: = для объявления// и инициализируем переменнуюy := 458// берём указатель на переменную используя//: = присваивая его с// адрес переменной yp := &yfmt.Println("Value stored in y = ", y)fmt.Println("Address of y = ", &y)fmt.Println("Value stored in pointer variable p = ", p)}- Выход:
Value stored in y = 458 Address of y = 0x414020 Value stored in pointer variable p = 0x414020
Разыменование указателя
Как мы знаем, оператор * также называется оператором разыменования. Он не только используется для объявления переменной указателя, но также используется для доступа к значению, хранящемуся в переменной, на которую указывает указатель, и которая обычно называется косвенной или разыменованной . * Оператор также называется значением по адресу . Давайте рассмотрим пример, чтобы лучше понять эту концепцию:
Пример:
// Программа Голанг для иллюстрации
// концепция разыменования указателя
package main
import "fmt"
func main() {
// используя ключевое слово var
// мы не определяем
// любой тип с переменной
var y = 458
// берём указатель на переменную используя
// ключевое слово var без указания
// тип
var p = &y
fmt.Println("Value stored in y = ", y)
fmt.Println("Address of y = ", &y)
fmt.Println("Value stored in pointer variable p = ", p)
// это разыменование указателя
// использование оператора * перед указателем
// переменная для доступа к сохраненному значению
// на переменную, на которую он указывает
fmt.Println("Value stored in y(*p) = ", *p)
}
Выход:
Value stored in y = 458 Address of y = 0x414020 Value stored in pointer variable p = 0x414020 Value stored in y(*p) = 458
Вы также можете изменить значение указателя или в ячейке памяти вместо назначения нового значения переменной.
Пример:
// Программа Голанг для иллюстрации
// вышеупомянутая концепция
package main
import "fmt"
func main() {
// используя ключевое слово var
// мы не определяем
// любой тип с переменной
var y = 458
// берём указатель на переменную используя
// ключевое слово var без указания
// тип
var p = &y
fmt.Println("Value stored in y before changing = ", y)
fmt.Println("Address of y = ", &y)
fmt.Println("Value stored in pointer variable p = ", p)
// это разыменование указателя
// использование оператора * перед указателем
// переменная для доступа к сохраненному значению
// на переменную, на которую он указывает
fmt.Println("Value stored in y(*p) Before Changing = ", *p)
// меняем значение y, присваивая
// новое значение для указателя
*p = 500
fmt.Println("Value stored in y(*p) after Changing = ",y)
}
Выход:
Value stored in y before changing = 458 Address of y = 0x414020 Value stored in pointer variable p = 0x414020 Value stored in y(*p) Before Changing = 458 Value stored in y(*p) after Changing = 500