Основы указателей в Go
Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy — урок 19 из 107.
Указатель — это переменная, которая хранит адрес памяти другой переменной. Вместо того чтобы хранить значение напрямую, он хранит местоположение, где это значение находится в памяти. Указатели являются фундаментальной частью Go и необходимы для эффективного манипулирования данными.
Чтобы создать указатель, используйте оператор & для получения адреса переменной, и оператор * для объявления типа указателя или доступа к значению по этому адресу.
x := 42
p := &x // p содержит адрес памяти x
fmt.Println(p) // 0xc000018030 (адрес памяти)
fmt.Println(*p) // 42 (значение по этому адресу)Оператор & означает «адрес» и возвращает указатель. Оператор *, при использовании с указателем, означает «значение по адресу» и называется разыменованием. Вы также можете изменить исходное значение через указатель.
x := 10
p := &x
*p = 25 // изменение значения через указатель
fmt.Println(x) // 25 (исходная переменная изменилась)Тип указателя записывается как *T, где T — это тип, на который он указывает. Указатель на int имеет тип *int.
var p *int // объявляет указатель на int
x := 100
p = &x // теперь p указывает на xНулевым значением указателя является nil, что означает, что он ни на что не указывает. Попытка разыменования указателя nil вызывает панику во время выполнения (runtime panic), поэтому всегда следите за тем, чтобы указатели были инициализированы перед использованием.
Задание
ЛегкоДавайте создадим простой механизм обмена значениями, который демонстрирует возможности указателей по изменению переменных через их адреса в памяти.
Вы организуете свой код в двух файлах:
swap.go: Создайте функцию с именемSwapValues, которая принимает два указателя*intв качестве параметров. Эта функция должна поменять местами значения, на которые указывают эти указатели — после её вызова каждая переменная должна содержать исходное значение другой переменной. Функция ничего не возвращает; она изменяет значения напрямую через указатели.main.go: Считайте два целых числа из входных данных, сохраните их в переменные, а затем используйте функциюSwapValuesдля обмена их значениями. Выведите оба значения до и после обмена, чтобы показать изменения.
Будут предоставлены следующие входные данные:
- Строка 1: Первое целое число
- Строка 2: Второе целое число
Формат вывода:
Before: a=[first] b=[second]
After: a=[first] b=[second]Например, для 10 и 25 ваш вывод должен быть:
Before: a=10 b=25
After: a=25 b=10Не забудьте использовать оператор & при передаче переменных в функцию и оператор * внутри функции для доступа и изменения фактических значений.
Шпаргалка
Указатель — это переменная, которая хранит адрес памяти другой переменной. Используйте оператор &, чтобы получить адрес переменной, и оператор *, чтобы объявить тип указателя или получить доступ к значению по этому адресу.
x := 42
p := &x // p хранит адрес памяти x
fmt.Println(p) // 0xc000018030 (адрес памяти)
fmt.Println(*p) // 42 (значение по этому адресу)Оператор & означает «адрес» и возвращает указатель. Оператор *, когда он используется с указателем, означает «значение по адресу» и называется разыменованием.
Вы можете изменить исходное значение через указатель:
x := 10
p := &x
*p = 25 // изменение значения через указатель
fmt.Println(x) // 25 (исходная переменная изменилась)Тип указателя записывается как *T, где T — это тип, на который указывает указатель:
var p *int // объявляет указатель на int
x := 100
p = &x // p теперь указывает на xНулевым значением указателя является nil. Попытка разыменовать указатель nil приводит к панике во время выполнения (runtime panic).
Попробуйте сами
package main
import "fmt"
func main() {
// Считать два целых числа из ввода
var a, b int
fmt.Scanln(&a)
fmt.Scanln(&b)
// Вывести значения перед перестановкой
fmt.Printf("Before: a=%d b=%d\n", a, b)
// TODO: Вызвать функцию SwapValues с указателями на a и b
// Не забудьте использовать оператор & для передачи адресов
// Вывести значения после перестановки
fmt.Printf("After: a=%d b=%d\n", a, b)
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП в Go
Внешние файлыРабочее пространство и модули GoПакеты и импортыЭкспортируемые и неэкспортируемые именаВведение в ООП в GoСтруктуры как классыОпределение методов структурПолучатели-указатели и получатели-значенияИнициализация структурФункции-конструкторыИтоги — Простой калькулятор4Интерфейсы
Введение в интерфейсыНеявная реализацияИнтерфейс как контрактПустой интерфейс (any)Утверждение типаПереключатель типовКомпозиция интерфейсовИнтерфейсы Stringer и ErrorПовторение: Калькулятор фигур7Инкапсуляция
Экспортируемые и неэкспортируемые поляИнкапсуляция на уровне пакетовГеттеры и сеттерыСокрытие информации в GoИтоги — Записи о студентах10Обобщения (Generics) (Go 1.18+)
Введение в GenericsПараметры типовОграничения типовОбобщенные структурыОбходной путь для обобщенных методовИтоги — Обобщенная коллекция13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн Abstract FactoryПаттерн ObserverПаттерн Strategy2Глубокое погружение в типы и структуры
Базовые и составные типыОпределение пользовательских типовТеги структурАнонимные структурыВложенные структурыНулевые значения и значения по умолчаниюПовторение — Контактная книга5Композиция вместо наследования
Почему в Go нет наследованияОсновы встраивания структурПродвижение методовВстраивание нескольких структурВстраивание против агрегацииЗатенение встроенных методовИтоги — Иерархия сотрудников8Обработка ошибок и ООП
Интерфейс errorПользовательские типы ошибокОбертывание ошибок (fmt.Errorf)Sentinel-ошибкиerrors.Is() и errors.As()Panic, Defer и RecoverИтоги — Парсер файлов11Стандартная библиотека и ООП
io.Reader и io.Writersort.InterfaceИнтерфейс fmt.Stringerencoding/json со структурамиИнтерфейс http.HandlerПовторение: модели REST API14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикMiddleware как Декоратор3Указатели и память
Основы указателей в GoУказатели на структурыПередача по значению и по ссылкеФункция new()Сборка мусора в GoПовторение: Конструктор связного списка6Полиморфизм в Go
Полиморфизм через интерфейсыУтиная типизация в GoПравила реализации интерфейсовПолиморфные коллекцииВнедрение зависимостейИтоги — Обработчик платежей9Конкурентность и ООП
Основы горутинКаналы и взаимодействиеБуферизованные и небуферизованные каналыОператор selectsync.Mutex и sync.RWMutexsync.WaitGroupПроектирование потокобезопасных структурПовторение — Worker Pool