Пройдите курс: Указатели

В этом учебнике мы обсудим указатели. Что же такое указатели?

Проще говоря, указатель — это переменная, которая используется для хранения в памяти адреса другой переменной.

Это можно использовать следующим образом:

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 году.

Основное внимание в нем уделяется простоте, надежности и эффективности. Он был разработан, чтобы объединить эффективность, скорость и безопасность статически типизированного и компилируемого языка с легкостью…

Посмотреть на GitHub

Оцените статью
devanswers.ru
Добавить комментарий