В этом учебнике мы обсудим указатели. Что же такое указатели?
Проще говоря, указатель — это переменная, которая используется для хранения в памяти адреса другой переменной.
Это можно использовать следующим образом:
var x *T
Где T — это тип, такой как int
, string
, float
и так далее.
Давайте на простом примере посмотрим, как это работает.
package main
import "fmt"
func main() {
var p *int
fmt.Println(p)
}
$ go run main.go
nil
Хм, это выводит nil
, но что такое nil
?
nil — это заранее объявленный идентификатор в Go, который представляет нулевое значение для указателей, интерфейсов, каналов, карт и срезов.
Это похоже на то, что мы изучали в разделе «Переменные и типы данных», где мы видели, что неинициализированный int
имеет нулевое значение 0, bool
— false, и так далее.
Итак, теперь давайте присвоим указателю значение.
package main
import "fmt"
func main() {
a := 10
var p *int = &a
fmt.Println("address:", p)
}
Мы используем оператор амперсанда &
для обращения к адресу переменной в памяти.
$ go run main.go
0xc0000b8000
Это должно быть значение адреса памяти переменной a
.
Разыменование
Мы также можем использовать оператор звездочки *
для значения, хранящегося в переменной, на которую указывает указатель. Это называется разыменованием.
Например, мы можем получить доступ к значению переменной a
через указатель p
, используя оператор звездочки *
.
package main
import "fmt"
func main() {
a := 10
var p *int = &a
fmt.Println("address:", p)
fmt.Println("value:", *p)
}
$ go run main.go
address: 0xc000018030
value: 10
Мы можем не только войти в него, но и изменить его с помощью указателя.
package main
import "fmt"
func main() {
a := 10
var p *int = &a
fmt.Println("before", a)
fmt.Println("address:", p)
*p = 20
fmt.Println("after:", a)
}
$ go run main.go
before 10
address: 0xc000192000
after: 20
По-моему, это очень здорово!
Указатели как аргументы функции
Указатели также можно использовать в качестве аргументов функции, когда нам нужно передать некоторые данные по ссылке.
Вот пример:
myFunction(&a)
...
func myFunction(ptr *int) {}
Новая функция
Существует и другой способ инициализации указателя. Мы можем использовать функцию new
, которая принимает тип в качестве аргумента, выделяет достаточно памяти для размещения значения этого типа и возвращает указатель на него.
Вот пример:
package main
import "fmt"
func main() {
p := new(int)
*p = 100
fmt.Println("value", *p)
fmt.Println("address", p)
}
$ go run main.go
value 100
address 0xc000018030
Указатель на указатель
Вот интересная идея… можем ли мы создать указатель на указатель. И ответ — да! Да, мы можем.
package main
import "fmt"
func main() {
p := new(int)
*p = 100
p1 := &p
fmt.Println("P value", *p, " address", p)
fmt.Println("P1 value", *p1, " address", p)
fmt.Println("Dereferenced value", **p1)
}
$ go run main.go
P value 100 address 0xc0000be000
P1 value 0xc0000be000 address 0xc0000be000
Dereferenced value 100
Обратите внимание, как значение p1
совпадает с адресом p
.
Также важно знать, что указатели в Go не поддерживают арифметику указателей, как в C или C++.
p1 := p * 2 // Compiler Error: invalid operation
Однако мы можем сравнить два указателя одного типа на равенство с помощью оператора ==
.
p := &a
p1 := &a
fmt.Println(p == p1)
Но почему?
Это подводит нас к вопросу на миллион долларов: зачем нам нужны указатели?
Однозначного ответа на него нет, указатели — это просто еще одна полезная функция, которая помогает нам эффективно мутировать наши данные без копирования большого количества данных.
И может быть применена для множества случаев использования.
В заключение добавлю, что если вы пришли из языка, в котором нет понятия об указателях, не паникуйте и постарайтесь сформировать мысленную модель того, как работают указатели.
Эта статья является частью моего открытого курса по Go, доступного на Github.
karanpratapsingh / go-course
Освойте основы и расширенные возможности языка программирования Go
Курс по Go
Привет, добро пожаловать на курс, и спасибо за изучение Go. Я надеюсь, что этот курс обеспечит вам отличный опыт обучения.
Этот курс также доступен на моем сайте, а также на Educative.io
Оглавление
-
Начало работы
- Что такое Go?
- Зачем изучать Go?
- Установка и настройка
-
Глава I
- Hello World
- Переменные и типы данных
- Форматирование строк
- Управление потоком данных
- Функции
- Модули
- Рабочие пространства
- Пакеты
- Полезные команды
- Сборка
-
Глава II
- Указатели
- Структуры
- Методы
- Массивы и фрагменты
- Карты
-
Глава III
- Интерфейсы
- Ошибки
- Паника и восстановление
- Тестирование
- Дженерики
-
Глава IV
- Параллелизм
- Гороутины
- Каналы
- Выбрать
- Пакет синхронизации
- Расширенные шаблоны параллелизма
- Контекст
-
Приложение
- Следующие шаги
- Ссылки
Что такое Go?
Go (также известный как Golang) — это язык программирования, разработанный в Google в 2007 году и открытый в 2009 году.
Основное внимание в нем уделяется простоте, надежности и эффективности. Он был разработан, чтобы объединить эффективность, скорость и безопасность статически типизированного и компилируемого языка с легкостью…