Указатели

Что такое указатели

Последнее обновление: 24.12.2017

Указатели представляют собой объекты, значением которых служат адреса других объектов (например, переменных).

Указатель определяется как обычная переменная, только перед типом данных ставится символ звездочки *. Например, определение указателя на объект типа int:

var p *int

Этому указателю можно присвоить адрес переменной типа int. Для получения адреса применяется операция &, после которой указывается имя переменной (&x).

package main

import "fmt"

func main() {
	
	var x int = 4		// определяем переменную
	var p *int 			// определяем указатель	
	p = &x				// указатель получает адрес переменной
	fmt.Println(p)		// значение самого указателя - адрес переменной x
}

Здесь указатель p хранит адрес переменной x. Что важно, переменная x имеет тип int, и указатель p указывает именно на объект типа int. То есть должно быть соответствие по типу. И если мы попробуем вывести адрес переменной на консоль, то увидим, что он представляет шестнадцатеричное значение:

0xc0420120a0

В каждом отдельном случае адрес может отличаться, но к примеру, в моем случае машинный адрес переменной x - 0xc0420120a0. То есть в памяти компьютера есть адрес 0xc0420120a0, по которому располагается переменная x.

По адресу, который хранит указатель, мы получить значение переменной x. Для этого применяется операция * или операция разыменования. Результатом этой операции является значение переменной, на которую указывает указатель. Применим данную операцию и получим значение переменной x:

package main

import "fmt"

func main() {
	
	var x int = 4
	var p *int  = &x				// указатель получает адрес переменной
	fmt.Println("Address:", p)		// значение указателя - адрес переменной x
	fmt.Println("Value:", *p)		// значение переменной x
}

Консольный вывод:

Address: 0xc0420c058
Value: 4

И также используя указатель, мы можем менять значение по адресу, который хранится в указателе:

var x int = 4
var p *int = &x
*p = 25
fmt.Println(x)		// 25

Для определения указателей можно использовать также сокращенную форму:

f := 2.3
pf := &f
	
fmt.Println("Address:", pf)
fmt.Println("Value:", *pf)

Пустой указатель

Если указателю не присвоен адрес какого-либо объекта, то такой указатель по умолчанию имеет значение nil (по сути отстутствие значения). Если мы попробуем получить значение по такому пустому указателю, то мы столкнемся с ошибкой:

var pf *float64
fmt.Println("Value:", *pf)	// ! ошибка, указатель не указывает на какой-либо объект

Поэтому при работе с указателями иногда бывает целесообразано проверять на значение nil:

var pf *float64
if pf != nil{
	fmt.Println("Value:", *pf)
}

Функция new

Переменная представляет именованный объект в памяти. Язык Go также позволяет создавать безымянные объекты - они также размещаются в памяти, но не имеют имени как переменные. Для этого применяется функция new(type). В эту функцию передается тип, объект которого надо создать. Функция возвращает указатель на созданный объект:

package main

import "fmt"

func main() {
	
	p := new(int) 
	fmt.Println("Value:", *p)		// Value: 0 - значение по умолчанию
	*p = 8							// изменяем значение
	fmt.Println("Value:", *p)		// Value: 8
}

В данном случае указатель p будет иметь тип *int, поскольку он указывает на объект типа int. Создаваемый объект имеет значение по умолчанию (для типа int это число 0).

Объект, созданный с помощью функции new, ничем не отличается от обычной переменной. Единственное что, чтобы обратиться к этому объекту - получить или изменить его адрес, необходимо использовать указатель.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850