Go: идиомы и паттерны проектирования
Қосымшада ыңғайлырақҚосымшаны жүктеуге арналған QRRuStore · Samsung Galaxy Store
Huawei AppGallery · Xiaomi GetApps

автордың кітабын онлайн тегін оқу  Go: идиомы и паттерны проектирования

 

Джон Боднер
Go: идиомы и паттерны проектирования
2022

Перевод С. Черников


 

Джон Боднер

Go: идиомы и паттерны проектирования. — СПб.: Питер, 2022.

 

ISBN 978-5-4461-1885-4

© ООО Издательство "Питер", 2022

 

Все права защищены. Никакая часть данной книги не может быть воспроизведена в какой бы то ни было форме без письменного разрешения владельцев авторских прав.

 

Отзывы о книге

Go — уникальный язык, и даже опытным программистам приходится «забыть» о том, как делаются некоторые вещи, и научиться иному подходу к программному обеспечению. Автор хорошо объясняет основные возможности языка, сопровождая теорию примерами идиоматического кода и описанием подводных камней и шаблонов проектирования.

Аарон Шлезингер (Aaron Schlesinger), ведущий разработчик, Microsoft

Джон на протяжении многих лет пользуется большим авторитетом в Go-сообществе; его высказывания и статьи часто несут в себе много полезного. Эта книга представляет собой руководство по изучению языка Go, рассчитанное на программистов. Она отлично сбалансирована в том плане, что хорошо объясняет необходимые вещи без пересказывания общеизвестных концепций.

Стив Франсия (Steve Francia), создатель Hugo, Cobra и Viper, ведущий менеджер по Go-продуктам, Google

Боднер предлагает нам настоящий Go. В ясной, «живой» манере он учит этому языку от самых его основ до таких продвинутых тем, как рефлексия и взаимодействие с кодом, написанным на языке C. Многочисленные примеры показывают, как следует писать идиоматический Go-код, уделяя особое внимание ясности и простоте. Также подробно объясняется, как те или иные базовые концепции влияют на поведение программ, как, например, указатели влияют на распределение памяти и сборку мусора. Эта книга поможет новичкам очень быстро выйти на должный уровень, и даже опытные Go-программисты найдут в ней что-то полезное.

Джонатан Амстердам (Jonathan Amsterdam), сотрудник подразделения Go-разработки, Google

Книга содержит важную вводную информацию о том, что именно делает уникальным язык программирования Go, а также о паттернах проектирования и идиомах, которые делают его чрезвычайно мощным. Джону Боднеру удалось показать связь между базовыми возможностями Go и его философией, направляя читателей писать Go-код так, как это было задумано создателями языка.

Роберт Лебовиц (Robert Liebowitz), разработчик, Morning Consult

Джон написал не просто руководство по Go; издание дает идиоматически и практически ориентированное понимание этого языка. Книга написана на основе богатого опыта Джона в компьютерной отрасли и поможет тем, кто хочет очень быстро научиться эффективно пользоваться этим языком.

Уильям Кеннеди (William Kennedy), управляющий партнер, Ardan Labs

Предисловие

Изначально я хотел назвать эту книгу «Скучный Go», потому что Go — это и правда очень скучно.

Конечно, немного странно писать книгу на скучную тему, но я сейчас все объясню. Язык Go обладает небольшим набором возможностей, что идет вразрез с большинством других современных языков программирования. Хорошо написанная программа на Go, как правило, отличается простотой, а часто и некоторым однообразием. Здесь нет наследования, обобщенных типов (по крайней мере пока), аспектно-ориентированного программирования, перегрузки функций и уж точно нет перегрузки операторов. Здесь нет сравнения с паттерном, нет именованных параметров и исключений, зато есть пугающие многих указатели. Модель обмена данными в Go не похожа на ту, что применяется в других языках, и основана на идеях 1970-х годов, как и алгоритм, используемый для сборщика мусора. Другими словами, работа с Go выглядит откатом в прошлое.

Однако если Go скучен, это еще не значит, что он примитивен. Для правильного использования этого языка необходимо четко понимать, как его возможности сочетаются друг с другом. Хотя вы вполне можете написать на Go такой код, который будет выглядеть почти так же, как код на Java или Python, но результат вас не слишком обрадует, и вы так и не поймете, к чему была вся эта суета. Вот тут-то и пригодится эта книга. Она познакомит вас с возможностями Go и объяснит, как лучше их использовать для написания расширяемого идиоматического кода.

Когда речь идет о создании чего-то, что должно служить нам долгие годы, такое качество, как «обычность», становится не минусом, а плюсом. Никто не захочет первым прокатиться на своей машине по мосту, созданному с использованием непроверенных технологий, которые инженер посчитал «крутыми». Современный мир зависит от программного обеспечения так же, как и от мостов, если не больше. Тем не менее во многие языки программирования добавляют массу новых компонентов, не задумываясь об их влиянии на «ремонтопригодность» кодовой базы, в то время как Go рассчитан на создание надежных программ, которые смогут улучшать десятки программистов на протяжении десятилетий.

Так что да, Go скучный и это здорово! Я надеюсь, книга научит вас создавать с помощью такого «скучного» кода потрясающие проекты.

Для кого написана книга

Целевая аудитория — разработчики, желающие изучить второй (или пятый) язык программирования. Она подойдет как новичкам, которые знают лишь то, что у Go есть забавный талисман, так и тем, кто уже успел прочитать краткое руководство по этому языку или даже написать на нем несколько фрагментов кода. Эта книга не просто рассказывает, как следует писать программы на Go, она показывает, как можно делать это идиоматически. Более опытные Go-разработчики найдут здесь советы по использованию новых возможностей языка.

Предполагается, что читатель уже умеет пользоваться таким инструментом разработчика, как система контроля версий (желательно Git) и IDE. Читатель должен быть знаком с такими базовыми понятиями информатики, как конкурентность и абстракция, поскольку в книге мы будем касаться этих тем применительно к Go. Одни примеры кода можно скачать с GitHub, а десятки других — запустить в онлайн-песочнице The Go Playground. Наличие соединения с интернетом необязательно, однако с ним будет проще изучать исполняемые примеры кода. Поскольку язык Go часто используется для создания и вызова HTTP-серверов, для понимания некоторых примеров читатель должен иметь общее представление о протоколе HTTP и связанных с ним концепциях.

Несмотря на то что большинство функций Go встречаются и в других языках, программы, написанные на Go, обладают иной структурой. В книге мы начнем с настройки среды разработки для языка Go, после чего поговорим о переменных, типах, управляющих конструкциях и функциях. Если вам захочется пропустить этот материал, постарайтесь удержаться от этого и все-таки ознакомиться с ним. Зачастую именно такие детали делают Go-код идиоматическим. Простые на первый взгляд вещи могут оказаться очень интересными, если вы присмотритесь к ним получше.

Условные обозначения

В этой книге используются следующие типографские обозначения.

Курсивный шрифт

Используется для выделения новых терминов.

Шрифт без засечек

Применяется для выделения URL-адресов, адресов электронной почты.

Моноширинный шрифт

Используется для записи примеров программ, а также для выделения в тексте таких элементов, как имена переменных и функций, базы данных, типы данных, переменные среды, операторы и ключевые слова, имена и расширения файлов.

Полужирный моноширинный шрифт

Применяется для выделения команд и другого текста, который должен вводиться пользователем без каких-либо изменений.

Курсивный моноширинный шрифт

Используется для обозначения в коде элементов, вместо которых следует подставить предоставленные пользователем значения или значения, зависящие от контекста.

Так обозначается совет или предложение.

 

 

Так обозначается примечание общего характера.

 

Так обозначается предупреждение.

Использование примеров программного кода

Вспомогательные материалы (примеры программного кода, упражнения и т.д.) доступны для скачивания по адресу https://github.com/learning-go-book.

При возникновении технических вопросов или проблем, связанных с использованием примеров кода, пожалуйста, обращайтесь по адресу электронной почты bookquestions@oreilly.com.

Книга призвана помочь вам в решении ваших задач. В большинстве случаев вы можете свободно использовать приводимые в этой книге примеры кода в своих программах и документации. Вам не нужно обращаться в издательство за разрешением, если вы не собираетесь воспроизводить существенную часть программного кода. Например, если вы разрабатываете программу и используете в ней несколько фрагментов кода из книги, вам не нужно обращаться за разрешением. Однако в случае продажи или распространения примеров из этой книги вы должны получить разрешение от издательства O’Reilly. Если вы отвечаете на вопросы, цитируя данную книгу или примеры из нее, то для этого не требуется разрешение. Но при включении значительного объема программного кода из этой книги в документацию вашего продукта необходимо получить разрешение издательства.

Мы не требуем, чтобы вы давали ссылку на первоисточник при цитировании, но будем признательны, если вы будете это делать. При этом обычно указывается название книги, имя ее автора, название издательства и номер ISBN. Например: «Go: идиомы и паттерны проектирования», Джон Боднер (Питер). Copyright 2021 Jon Bodner, 978-5-4461-1885-4».

Если у вас возникнут какие-либо сомнения относительно правомерности использования примеров кода, вы всегда можете связаться с нами по адресу permissions@oreilly.com.

Благодарности

Хоть и считается, что писательство — это индивидуальное занятие, книга не может появиться на свет без помощи множества других людей. Однажды я сказал Кармен Андо (Carmen Andoh), что собираюсь написать книгу по языку Go, и на конференции GopherCon 2019 она познакомила меня с Зан Маккуэйд (Zan McQuade) из компании O’Reilly. Зан помогла мне заключить договор с издательством, после чего регулярно консультировала меня по мере моего прогресса в написании книги. Мишель Кронин (Michele Cronin) редактировала мои тексты, высказывала замечания и выслушивала меня, когда я неизбежно сталкивался с трудностями. Технический редактор Тоня Трибула (Tonya Trybula) и литературный редактор Бет Келли (Beth Kelly) довели мою рукопись до пригодного для печати вида.

По мере написания книги я получал важные замечания (и слова поддержки) от многих людей, в числе которых были Джонатан Алтмэн (Jonathan Altman), Джонатан Амстердам (Jonathan Amsterdam), Джонни Рэй Остин (Johnny Ray Austin), Крис Фойербах (Chris Fauerbach), Крис Хайнс (Chris Hines), Билл Кеннеди (Bill Kennedy), Тони Нельсон (Tony Nelson), Фил Перл (Phil Pearl), Лиз Райс (Liz Rice), Аарон Шлезингер (Aaron Schlesinger), Крис Стаут (Chris Stout), Капил Тхангавелу (Kapil Thangavelu), Клер Тривисонно (Claire Trivisonno), Фолькер Уриг (Volker Uhrig), Джефф Уэндлинг (Jeff Wendling) и Крис Сарагоса (Kris Zaragoza). Особых слов признательности заслуживает Роб Лебовиц (Rob Liebowitz), подробные замечания и быстрые ответы которого сделали эту книгу гораздо лучше.

Моей семье приходилось мириться с тем, что я проводил вечера и выходные дни за компьютером вместо того, чтобы проводить это время с ними. Моя жена Лора великодушно делала вид, что я не разбудил ее, когда я добирался до кровати в час ночи или еще позже.

Наконец, хочется вспомнить о тех людях, которые направили меня по этому пути четыре десятилетия назад. Первым из них был отец моего друга детства Пол Голдштейн (Paul Goldstein). В 1982 году он показал нам компьютер Commodore PET, ввел команду PRINT2+2 и нажал клавишу ввода. Я был поражен, когда на экране появилась цифра 4, и заболел этим раз и навсегда. Спустя какое-то время Пол научил меня программировать и даже на несколько недель одолжил свой компьютер. А вторым человеком была моя мама, которую я должен поблагодарить за то, что она поощряла мой интерес к программированию и компьютерам, даже толком не понимая, что это такое. В свое время она купила мне картридж для игровой приставки Atari 2600, позволявший писать программы на языке BASIC, компьютеры Commodore VIC-20 и Commodore 64, а также книги по программированию, после прочтения которых у меня появилась мечта когда-нибудь написать свою собственную книгу.

Спасибо всем вам за то, что помогли мне сделать эту мечту реальностью!

От издательства

Ваши замечания, предложения, вопросы отправляйте по адресу comp@piter.com (издательство «Питер», компьютерная редакция).

Мы будем рады узнать ваше мнение!

На веб-сайте издательства www.piter.com вы найдете подробную информацию о наших книгах.

Согласно комментарию автора на странице книги на сайте O’Reilly, инструмент golint не поддерживается. По этой причине мы удалили из главы 1 подраздел, посвященный golint.

Глава 1. Настройка среды разработки для языка Go

Любой язык программирования нуждается в среде разработки, и Go не исключение. Если вы уже успели написать на Go одну-две программы, то у вас уже, вероятно, имеется рабочая среда, но при этом вы могли упустить из виду некоторые новые методы и инструменты. Если же вы в первый раз настраиваете свой компьютер для разработки на Go, не беспокойтесь: установка средств поддержки этого языка не представляет большого труда. Настроив среду и убедившись, что это было сделано правильно, мы напишем простую программу и опробуем несколько способов компиляции и запуска Go-кода, после чего рассмотрим несколько инструментов и методов, упрощающих процесс Go-разработки.

Установка средств разработки для языка Go

Чтобы приступить к написанию кода на Go, нужно установить средства разработки. Последнюю версию этих инструментов можно скачать с официального сайта языка Go (https://golang.org/dl). Скачайте и установите версию, подходящую для вашей платформы. Установочные пакеты с расширением .pkg для Mac и с расширением .msi для Windows автоматически установят Go в нужном каталоге, удалят ранее установленные файлы и разместят двоичный файл языка Go в соответствии с путем по умолчанию для исполняемых файлов.

Для платформы Mac средства разработки для языка Go можно установить с помощью менеджера пакетов Homebrew (https://brew.sh), выполнив ­команду brew install go. Для Windows это можно сделать с помощью ме­неджера пакетов Chocolatey (https://chocolatey.org), выполнив команду choco install golang.

Версии установочных пакетов для Linux и FreeBSD представляют собой архивы с расширением .tar, которые распаковываются в каталог с именем go. Скопируйте этот каталог в /usr/local и добавьте путь /usr/local/go/bin в переменную среды $PATH, чтобы сделать доступной команду go:

$ tar -C /usr/local -xzf go1.15.2.linux-amd64.tar.gz

$ echo 'export PATH=$PATH:/usr/local/go/bin' >> $HOME/.profile

$ source $HOME/.profile

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

Чтобы убедиться, что ваша среда настроена правильно, откройте окно терминала или командной строки и введите команду:

$ go version

Если все было настроено правильно, то вы увидите что-то наподобие следу­ющего:

go version go1.15.2 darwin/amd64

Это сообщение говорит о наличии компилятора Go версии 1.15.2 для Mac OS. (Darwin — это название ядра в Mac OS, а amd64 — название 64-разрядной процессорной архитектуры от AMD и Intel.)

Если вместо сообщения с описанием версии вы увидите сообщение об ошибке, значит, у вас нет файла go в каталоге, заданном в качестве пути для исполняемых файлов, или в этом файле находится другая программа с таким же именем. В Mac OS или других Unix-подобных системах можно выяснить, какой файл go запускается и запускается ли вообще, с помощью команды whichgo. Если это не файл, расположенный по адресу /usr/local/go/bin/go, скорректируйте свой путь для исполняемых файлов.

Если вы работаете в Linux или FreeBSD, ошибка может состоять в том, что вы установили 64-разрядную версию средств разработки для языка Go в 32-разрядной системе или версию для другой процессорной архитектуры.

Рабочее пространство Go

С момента появления Go в 2009 году было введено несколько изменений в способе организации Go-кода и его зависимостей. Из-за этого вы можете найти множество противоречивых рекомендаций, большая часть которых уже устарела.

Сегодня здесь действует простое правило: вы можете организовывать свои проекты любым удобным вам способом. Однако все же предполагается, что вы будете использовать единое рабочее пространство для сторонних инструментов Go, устанавливаемых с помощью команды goinstall (см. подраздел «Установка сторонних инструментов для Go» на с. 23). По умолчанию это рабочее пространство размещается в каталоге $HOME/go; при этом исходный код для этих инструментов хранится в каталоге $HOME/go/src, а скомпилированные двоичные файлы — в каталоге $HOME/go/bin. Вы можете использовать эти настройки по умолчанию или задать другое расположение рабочего пространства с помощью переменной среды $GOPATH.

Вне зависимости от того, какой вариант расположения вы решили использовать, рекомендуется явно определить переменную GOPATH и добавить каталог $GOPATH/bin в переменную, задающую путь для исполняемых файлов. Явное определение переменной GOPATH позволяет ясно указать, где находится рабочее пространство языка Go, а добавление каталога $GOPATH/bin в качестве дополнительного пути для исполняемых файлов упрощает запуск сторонних инструментов, которые устанавливаются с помощью команды goinstall и о которых мы поговорим чуть позже.

Если вы работаете с Unix-подобной системой, использующей командную оболочку bash, необходимо добавить следующие строки в файл .profile. (Если вы используете командную оболочку zsh, добавьте эти строки в файл .zshrc.)

export GOPATH=$HOME/go

export PATH=$PATH:$GOPATH/bin

Чтобы эти изменения вступили в силу, выполните команду source$HOME/.profile в текущем окне терминала.

Если вы работаете в Windows, выполните следующие команды в окне командной строки:

setx GOPATH %GOPATH%\go

setx path "%path%;%USERPROFILE%\bin"

Чтобы эти изменения вступили в силу, закройте текущее окно командной строки и откройте новое.

Инструмент go принимает во внимание и ряд других переменных среды. Вы можете получить полный список этих переменных вместе с кратким описанием каждой из них, выполнив команду goenv. Многие из этих переменных управляют низкоуровневым поведением, которое можно спокойно проигнорировать, однако мы все же рассмотрим некоторые из них при обсуждении модулей и перекрестной компиляции.

В некоторых онлайн-источниках рекомендуется определить переменную среды GOROOT. В ней задается расположение установленных средств разработки для языка Go. Теперь в этом уже нет необходимости: инструмент go определяет расположение автоматически.

Команда go

В комплект поставки языка Go входит достаточно много средств разработки, запускаемых с помощью команды go: компилятор, средства форматирования и статического анализа кода, менеджер зависимостей, средство тестирования и многое другое. Мы будем знакомиться с большинством из них по мере того, как станем учиться создавать высококачественный идиоматический Go-код. Начнем с инструментов, используемых для компиляции Go-кода, и попробуем скомпилировать с помощью команды go простое приложение.

Команды go run и go build

С помощью go мы можем выполнить две похожие команды: gorun и gobuild. Обе принимают на вход отдельный файл Go, список Go-файлов или имя пакета. Создадим простую программу и посмотрим, что произойдет, когда мы воспользуемся этими командами.

Команда go run

Начнем с команды gorun. Создайте каталог с именем ch1, после чего откройте текстовый редактор, введите следующий текст и сохраните его в файле с именем hello.go внутри каталога ch1:

package main

 

import "fmt"

 

func main() {

    fmt.Println("Hello, world!")

}

После этого откройте окно терминала или командной строки и выполните в нем следующую команду:

go run hello.go

На экран будет выведена фраза Hello,world!. Если вы проверите содержимое каталога после выполнения команды gorun, то увидите, что в нем не появился двоичный файл и он по-прежнему содержит только созданный нами файл hello.go. Здесь вы можете спросить: почему так происходит, ведь Go вроде бы компилируемый язык?

На самом деле команда gorun, как и положено, компилирует ваш код в двоичный файл, но этот файл сохраняется во временном каталоге. Эта команда компилирует двоичный файл, выполняет его из временного каталога и удаляет его после завершения работы программы. В силу этого команду gorun удобно использовать для тестирования небольших программ или при использовании языка Go в качестве языка сценариев.

Вводите команду go run, когда требуется использовать Go-программу в качестве скрипта или выполнить быстрый запуск исходного кода.

Команда go build

В большинстве случаев вам потребуется скомпилировать двоичный файл для последующего использования. Здесь вам поможет команда gobuild. Введите в окне терминала такую команду:

go build hello.go

Она создаст в текущем каталоге исполняемый файл с именем hello (или hello.exe в Windows). Если вы запустите его, то на экран, как и следовало ожидать, будет выведена фраза Hello,world!.

Имя этого двоичного файла совпадает с тем именем файла или пакета, которое вы передали команде. Если вам нужно сохранить приложение под другим именем или в другом каталоге, используйте флаг -o. Например, чтобы скомпилировать код в двоичный файл с именем hello_world, нужно ввести следующую команду:

go build -o hello_world hello.go

Используйте команду go build для создания распространяемого файла, который будет использоваться другими пользователями. Именно это требуется сделать в большинстве случаев. Используйте флаг -o, чтобы задать другое имя или расположение двоичного файла.

Установка сторонних инструментов для Go

Хотя некоторые Go-разработчики и предпочитают распространять свои программы в виде скомпилированных двоичных файлов, написанные на Go инструменты также можно скомпилировать из исходного кода и установить в свое рабочее пространство Go с помощью команды goinstall.

В Go применяется не такой, как в большинстве других языков, метод публикации кода. Вместо того чтобы использовать такой централизованный сервис, как Maven Central в случае Java или реестр NPM в случае JavaScript, Go-разработчики распространяют свои проекты посредством репозиториев исходного кода. В качестве аргумента команде goinstall передается расположение репозитория исходного кода интересующего вас проекта, за которым следует символ @ и нужная версия этого инструмента (если нужно установить последнюю версию, укажите @latest). Когда вы запустите эту команду, она скачает, скомпилирует и установит указанный инструмент в каталог $GOPATH/bin.

Рассмотрим небольшой пример, используя такой отличный Go-инструмент, как нагрузочное тестирование HTTP-серверов под названием hey. Эта программа позволяет протестировать любой выбранный вами сайт или написанное вами приложение. Установить ее можно следующим образом:

$ go install github.com/rakyll/hey@latest

go: downloading github.com/rakyll/hey v0.1.4

go: downloading golang.org/x/net v0.0.0-20181017193950-04a2e542c03f

go: downloading golang.org/x/text v0.3.0

Команда скачивает программу hey и все ее зависимости, компилирует ее и устанавливает двоичный файл в каталоге $GOPATH/bin.

Как будет подробно рассказано в разделе «Прокси-серверы модулей» на с. 248, содержимое Go-репозиториев кэшируется на прокси-серверах. В зависимости от конкретного репозитория и значений, заданных в переменной среды GOPROXY, команда go install может производить скачивание либо с прокси-сервера, либо непосредственно из репозитория. При скачивании непосредственно из репозитория эта команда использует установленные на вашей машине инструменты командной строки. Так, например, для скачивания из репозитория, расположенного на сайте GitHub, у вас должна быть установлена система контроля версий Git.

Теперь, когда мы уже скомпилировали и установили программу hey, можем запустить ее с помощью следующей команды:

$ hey https://www.golang.org

 

Summary:

  Total:        0.6864 secs

  Slowest:      0.3148 secs

  Fastest:      0.0696 secs

  Average:      0.1198 secs

  Requests/sec: 291.3862

Если определенный инструмент уже установлен на вашей машине и вам нужно обновить его до последней версии, запустите команду goinstall еще раз, указав в параметре новую версию или слово latest:

go install github.com/rakyll/hey@latest

Разумеется, написанные на Go инструменты совсем не обязательно оставлять в рабочем пространстве Go: это обычные исполняемые двоичные файлы, которые можно разместить в любом каталоге. Точно так же вам не обязательно распространять написанные на Go программы посредством команды goinstall: вместо этого можно предложить для скачивания двоичный файл. Однако эту команду очень удобно использовать для распространения Go-программ среди разработчиков.

Форматирование кода

Создатели языка Go прежде всего хотели создать язык, который позволял бы писать код эффективно. Это означало, что они должны были использовать простой синтаксис и быстрый компилятор. Кроме того, это вынудило создателей языка Go пересмотреть подход к форматированию кода. В то время как другие языки предоставляют вам большую свободу в плане способа организации кода, Go не делает этого. Он обязывает использовать стандартный формат, что существенно облегчает написание инструментов для работы над исходным кодом. Это упрощает компилятор и делает возможным создание продвинутых генераторов кода.

У этого подхода есть и еще одно преимущество. Разработчики раньше тратили очень много времени на «войну форматов». Благодаря тому, что Go определяет стандартный способ форматирования кода, Go-разработчикам не приходится спорить относительно того, какой стиль размещения фигурных скобок лучше использовать или как лучше задавать отступы: с помощью символов табуляции или с помощью пробелов. Так, например, для задания отступов в Go-коде используются символы табуляции, и, если открывающая фигурная скобка не находится в той же строке, что и начинающие этот блок команда или объявление, это считается ошибкой синтаксиса.

Среди Go-разработчиков бытует мнение, что создатели языка Go решили использовать стандартный формат для того, чтобы исключить споры в отношении формата, и уже после этого обнаружили преимущества данного подхода в плане создания инструментов. Однако Расс Кокс (Russ Cox) пуб­лично заявил о том, что его исходным мотивом было упрощение процесса создания инструментов (https://oreil.ly/rZEUv).

Правило вставки точки с запятой

Команда gofmt не исправляет ошибочное размещение фигурной скобки не в той строке, что объясняется наличием правила вставки точки с запятой. Подобно языкам C и Java, Go требует, чтобы каждый оператор заканчивался символом «точка с запятой». Однако Go-разработчики никогда не расставляют символы «точка с запятой» вручную, поскольку компилятор языка Go делает это автоматически в соответствии с очень простым правилом, суть которого изложена в кратком руководстве «Эффективный Go» (https://oreil.ly/hTOHU):

Если символу новой строки предшествует одна из следующих лексем, то лексический анализатор вставляет после нее символ «точка с запятой»:

• идентификатор (включая такие слова, как int и float64);

• один из базовых литералов, таких как число или строковая константа;

• одна из следующих лексем: break, continue, fallthrough, return, ++, ––, ), }.

Зная, что в Go действует это простое правило, легко понять, почему невозможно исправить размещение в неправильном месте фигурной скобки. Если, например, вы напишете следующий код:

func main()

{

    fmt.Println("Hello, world!")

}

то благодаря правилу вставки точки с запятой будет распознан символ ) в конце строки funcmain(), а код приведен к следующему виду:

func main();

{

    fmt.Println("Hello, world!");

};

что не будет корректным Go-кодом.

Правило вставки точки с запятой — одна из тех вещей, которые делают компилятор языка Go проще и быстрее, в то же время обеспечивая единый стиль программирования, что весьма и весьма разумно.

 

В набор средств разработки языка Go входит команда gofmt, которая автоматически форматирует ваш код в соответствии со стандартным форматом. Она позволяет исправить неверно заданные отступы, выравнивает поля в структурах и обеспечивает правильные интервалы между операторами.

Существует расширенная версия команды gofmt под названием goimports, которая также приводит в порядок операторы импорта. Она располагает их в алфавитном порядке, удаляет неиспользуемые операторы и добавляет операторы импорта недостающих, по ее мнению, пакетов. Поскольку она не всегда точно угадывает, каких пакетов вам не хватает, добавлять операторы импорта лучше вручную.

Скачать goimports можно с помощью команды goinstallgolang.org/x/tools/cmd/goimports@latest. Чтобы применить ее к файлам своего проекта, выполните следующую команду:

goimports -l -w .

Флаг -l дает goimports указание вывести в консоль список неправильно отформатированных файлов. Флаг -w дает указание непосредственно изменить эти файлы. Символ «точка» указывает, что нужно проверить все файлы, находящиеся в текущем каталоге и во всех подкаталогах.

Всегда используйте go fmt или программу goimports перед тем, как компилировать свой код!

Выбор инструментов

Хотя, как мы уже успели убедиться, написать небольшую программу на Go можно, используя только текстовый редактор и команду go, для работы над более крупными проектами вам, вероятно, потребуются более продвинутые инструменты. К счастью, к настоящему времени уже созданы отличные средства поддержки языка Go для большинства существующих текстовых редакторов и интегрированных сред разработки (https://oreil.ly/MwCWT). Если вы еще не определились с выбором среды разработки, то двумя наиболее популярными вариантами в случае языка Go являются редактор кода Visual Studio Code и интегрированная среда разработки Goland.

Visual Studio Code

Если вы хотите найти бесплатную среду разработки, то лучшим выбором будет редактор кода Visual Studio Code от компании Microsoft (https://oreil.ly/zktT8). За время, прошедшее с момента его появления в 2015 году, VS Code успел приобрести чрезвычайно большую популярность среди разработчиков. Хотя поддержка языка Go не входит в его «комплект поставки», его можно превратить в среду разработки для языка Go, скачав расширение для поддержки этого языка из галереи расширений.

Поддержка языка Go в редакторе VS Code обеспечивается с помощью сторонних инструментов. Это включает в себя комплект средств разработки языка Go, отладчик Delve (https://oreil.ly/sosLu) и gopls (https://oreil.ly/TLapT) — языковой сервер для языка Go, созданный командой разработчиков этого языка. При этом комплект средств разработки языка Go вы должны установить самостоятельно, а Delve и gopls для вас установит Go-расширение редактора.

Установив и настроив этот инструмент, можете открыть свой проект и приступить к работе над ним. Окно вашего проекта должно выглядеть примерно так, как показано на рис. 1.1. Основы работы с Go-расширением редактора VS Code демонстрируются во вводном видео «Приступая к работе с VS Code Go» (https://oreil.ly/XhoeB).

 

Рис. 1.1. Visual Studio Code

Что такое языковой сервер? Это стандартная спецификация API, позволяющего редакторам реализовать такие интеллектуальные функции редак­тирования, как автодополнение и статический анализ кода, поиск мест ­использования методов и т.д. Для большей информации ознакомьтесь с протоколом языкового сервера (https://oreil.ly/2T2fw).

GoLand

GoLand (https://oreil.ly/6cXjL) — это ориентированная на язык Go интегрированная среда разработки (IDE) от компании JetBrains. Хотя компания JetBrains в первую очередь славится своими инструментами для разработки на Java, это не мешает GoLand быть прекрасной средой разработки для языка Go. Как можно убедиться, взглянув на рис. 1.2, пользовательский интерфейс среды разработки GoLand выглядит практически так же, как интерфейс сред разработки IntelliJ, PyCharm, RubyMine, WebStorm и Android Studio или любой другой IDE от компании JetBrains. Поддержка Go в GoLand включает в себя такие вещи, как рефакторинг, выделение синтаксиса, автодополнение и навигация по коду, всплывающие подсказки с описанием типов и функций, отладчик, отслеживание покрытия кода и многое другое. Помимо поддержки языка Go, среда разработки

 

Рис. 1.2. GoLand

GoLand также предлагает инструменты для работы с JavaScript/HTML/CSS и базами данных SQL. В отличие от редактора кода VS Code, для использования среды разработки GoLand вам не потребуется скачивать никаких дополнительных инструментов.

Если у вас уже есть подписка на IntelliJ IDEA Ultimate (или право на бесплатное использование этого продукта), можете добавить поддержку Go в него, установив соответствующий плагин. В противном случае придется заплатить за среду разработки GoLand, у которой нет бесплатной версии.

Онлайн-песочница

Существует еще один важный инструмент для разработки на языке Go, который к тому же не требует установки. Перейдя по адресу http://play.golang.org, вы попадете на страницу онлайн-песочницы для языка Go, внешний вид которой показан на рис. 1.3. Если вам приходилось использовать такие инструменты командной строки, как irb, node или python, то вы увидите, что работа с этой онлайн-песочницей осуществляется во многом так же. Она позволяет вам запускать и показывать другим пользователям небольшие программы. Введите свою программу в поле ввода и нажмите кнопку Run (Выполнить) для ее выполнения. Нажатие кнопки Format (Форматировать) запустит для вашей программы

 

Рис. 1.3. Онлайн-песочница

команду gofmt и, если при этом будет установлен флажок Imports (Импорты), также приведет в порядок операторы импорта, как это делает утилита goimports. Кнопка Share (Поделиться) позволяет создать уникальный URL-адрес для того, чтобы предоставить ссылку на программу другим пользователям или вернуться к работе над ней в дальнейшем (хотя эти ссылки и сохраняются в течение долгого времени, я все же не стал бы использовать онлайн-песочницу в качестве репозитория исходного кода).

Как показывает рис. 1.4, вы даже можете сымитировать работу с несколькими файлами, отделив каждый файл с помощью строки вида ––filename.go--.

Используя онлайн-песочницу, не забывайте о том, что она работает на другой машине (а если быть точнее, на машине компании Google), что ограничивает вашу свободу действий. При этом всегда используется последняя стабильная версия языка Go. Вы не можете устанавливать сетевые соединения, и, кроме того, ваш процесс может быть остановлен, если он будет работать слишком долго или задействовать слишком много памяти. Если в вашей программе используется время, установите в качестве начала отсчета 10 ноября 2009 года, 23:00:00 UTC (это дата и время первой официальной презентации языка Go). Однако даже эти ограничения не мешают онлайн-песочнице быть очень полезным инструментом,

 

Рис. 1.4. Онлайн-песочница поддерживает использование нескольких файлов

который позволяет опробовать новые идеи без создания нового проекта на своей машине. В этой книге я буду часто использовать ссылки на онлайн-песочницу, чтобы вы могли запускать примеры кода, не копируя их на свой компьютер.

Никогда не размещайте в онлайн-песочнице такую конфиденциальную информацию, как сведения о вашей личности, пароли и секретные ключи! Если вы нажмете кнопку Share (Поделиться), то эта информация будет сохранена на серверах компании Google и станет доступной для всех пользователей, получивших соответствующую ссылку. Если вы по ошибке предоставили доступ к такой информации, свяжитесь с компанией Google по адресу security@golang.org и сообщите, какой URL-адрес вам нужно удалить и по какой причине это нужно сделать.

make-файлы

IDE удобно использовать, но трудно автоматизировать. Сегодня процесс программной разработки подразумевает использование воспроизводимых и автоматизируемых операций компиляции, которые может выполнять кто угодно, где угодно и когда угодно, что позволяет не обращать внимания на распространенную отговорку разработчиков: «На моей машине все работает!» Реализовать такой подход можно с помощью скрипта, в котором будут определены этапы процесса компиляции. Go-разработчики для этой цели используют утилиту make. Если вы не знакомы с этой утилитой, напомню, что она с 1976 года применяется для компиляции программ в операционных системах Unix.

Например, в случае нашего простого проекта можно использовать следующий make-файл:

.DEFAULT_GOAL := build

 

fmt:

        go fmt ./...

.PHONY:fmt

 

lint: fmt

        golint ./...

.PHONY:lint

 

vet: fmt

        go vet ./...

.PHONY:vet

 

build: vet

        go build hello.go

.PHONY:build

Даже если вам не приходилось использовать make-файлы раньше, будет совсем не трудно разобраться в том, что здесь происходит. Каждая из выполняемых операций называется целью. Директива цели по умолчанию .DEFAULT_GOAL указывает, какая цель должна выполняться в том случае, если не будет указано ни одной цели. В данном случае в качестве цели по умолчанию задана операция build. Далее следуют определения целей. В каждом из них сначала указывается имя цели, а за ним, после знака двоеточия (:), — имена целей, запущенных перед выполнением данной цели (как, например, vet в определении build:vet). Задачи, которые выполняются целью, находятся в строках с отступом после цели. (Директива фиктивной цели .PHONY не дает утилите make запутаться в том случае, если в вашем проекте будет создан каталог с таким же именем, как у цели.)

Разместив этот make-файл в каталоге ch1, выполните следующую команду:

make

На экран будет выведено следующее:

go fmt ./...

go vet ./...

go build hello.go

Таким образом, с помощью всего одной команды вы обеспечите правильное форматирование кода, проверите его на наличие неочевидных программных ошибок и скомпилируете его. Вы также можете запустить только линтер с помощью команды makelint, только утилиту vet с помощью команды makevet или только средство форматирования с помощью команды makefmt. Возможно, это и нельзя назвать большим улучшением, однако гарантированный запуск средств форматирования и статического анализа перед тем, как разработчик (или скрипт, запущенный сервером непрерывной интеграции) запустит операцию компиляции, означает, что вы никогда не пропустите ни одного шага.

Одним из недостатков make-файлов является то, что они требуют определенной внимательности: каждую из указанных для цели задач нужно обязательно снабдить отступом с помощью символа табуляции. Поддержка этих файлов также не входит в число стандартных возможностей операционной системы Windows. Если вы собираетесь писать Go-код на машине с Windows, вам сначала потребуется установить утилиту make. Самый простой способ это сделать сводится к тому, чтобы сначала установить менеджер пакетов наподобие Chocolatey (https://chocolatey.org), а затем установить утилиту make с его помощью (в случае Chocolatey это можно сделать с помощью команды chocoinstallmake).

Обновление средств разработки

Как и в случае любого другого языка программирования, средства разработки языка Go регулярно подвергаются изменениям. Поскольку Go-программы представляют собой файлы нативного двоичного кода, для запуска которых не требуется отдельная среда выполнения, вы можете не бояться того, что после обновления ваших средств разработки перестанут работать ранее развернутые программы. Вы можете совершенно спокойно запускать на одном компьютере или в одной виртуальной машине программы, скомпилированные с использованием разных версий языка Go.

Начиная с версии Go 1.2, крупные релизы выходят с интервалом примерно шесть месяцев. По мере необходимости также выпускаются небольшие релизы с исправлениями программных ошибок и проблем безопасности. В силу того, что команда разработчиков языка Go применяет быстрые циклы разработки и старается обеспечивать обратную совместимость, релизы языка Go обычно носят инкрементный характер и вносят не слишком много изменений. В статье «Обязательства по совместимости языка Go» (https://oreil.ly/p_NMY) подробно объясняется, каким образом команда разработчиков языка Go планирует не допускать изменений, способных нарушить работоспособность имеющегося Go-кода. Там говорится, что команда разработчиков не будет вносить в язык или стандартную библиотеку изменения, ломающие обратную совместимость, в случае любой версии языка Go, начинающейся с 1, за исключением изме­нений, необходимых для исправления программных ошибок или проблем ­безопасности. В то же время команда разработчиков может вносить (и уже вносила) несовместимые изменения во флаги или функциональность ­команд go.

Несмотря на гарантии обратной совместимости, при внесении изменений не исключены программные ошибки, поэтому, вполне естественно, у вас возникнет желание убедиться, что новый релиз не нарушает работоспособность ваших программ. Один из способов это сделать состоит в том, чтобы установить вторую рабочую среду для языка Go. Например, если сейчас вы используете версию 1.5.2 и хотели бы опробовать версию 1.15.6, можно выполнить следующие команды:

$ go get golang.org/dl/go.1.15.6

$ go1.15.6 download

После этого вместо команды go можно будет применить команду go1.15.6, чтобы посмотреть, будут ли работать ваши программы при использовании версии 1.15.6:

$ go1.15.6 build

Убедившись в том, что ваш код будет работать, вы можете удалить вторую рабочую среду. Для этого нужно найти и удалить соответствующую переменную GOROOT, а затем удалить двоичный файл этой среды из каталога $GOPATH/bin. В Mac OS, Linux и BSD это можно сделать следующим образом:

$ go1.15.6 env GOROOT

/Users/gobook/sdk/go1.15.6

$ rm -rf $(go1.15.6 env GOROOT)

$ rm $(go env GOPATH)/bin/go1.15.6

Когда вы будете готовы к тому, чтобы обновить установленные на вашей машине средства разработки языка Go, проще всего это будет сделать на платформах Mac и Windows. Если вы производили установку с помощью менеджера пакетов brew или chocolatey, то с его помощью можно выполнить и обновление. Если же вы скачивали установочный пакет со страницы https://golang.org/dl, воспользуйтесь последней версией этого пакета, которая в ходе установки удалит с машины старую версию.

На машинах с Linux и BSD необходимо скачать последнюю версию, переместить старую версию в резервный каталог, распаковать новую версию и удалить старую версию.

$ mv /usr/local/go /usr/local/old-go

$ tar -C /usr/local -xzf go1.15.2.linux-amd64.tar.gz

$ rm -rf /usr/local/old-go

Резюме

В этой главе вы узнали, как установить и настроить среду разработки для языка Go. Мы рассмотрели инструменты для компиляции Go-программ и обеспечения хорошего уровня качества кода. Теперь, когда у нас есть готовая среда, можем перейти к следующей главе, где рассмотрим встроенные типы языка Go и способы объявления переменных.

Глава 2. Простые типы и объявление переменных

Теперь, когда мы уже настроили среду разработки, пришло время перейти к изу­чению возможностей языка Go и наилучших способов их использования. Под наилучшими здесь имеется в виду то, что код будет удовлетворять главному принципу: программа должна быть написана так, чтобы сразу было понятно, для чего она предназначена. По мере изучения вы познакомитесь с различными подходами и поймете, почему тот или иной подход позволяет получить более ясный код.

Начнем с рассмотрения простых типов и переменных. Хотя эти понятия и знакомы каждому программисту, в Go некоторые вещи делаются по-другому, что отличает его от других языков.

Встроенные типы

В языке Go есть много тех же встроенных типов, что и в других языках: логические значения, целые числа, числа с плавающей точкой и строки. Идиоматическое использование этих типов иногда вызывает затруднения у разработчиков, ранее писавших на других языках. Вы познакомитесь с этими типами и узнаете, как они применяются в Go. Но перед этим остановимся на ряде концепций, которые применимы ко всем типам.

Нулевое значение

Go, как и большинство других современных языков, по умолчанию присваивает нулевое значение любой переменной, которая объявлена, но не имеет значения. Наличие четко заданного нулевого значения делает код более ясным и устраняет источник программных ошибок, часто встречающихся в программах на C и C++. При этом у каждого типа есть свое нулевое значение.

Литералы

Под литералом в Go понимается запись числа, символа или строки. Существует четыре вида литералов (но есть и очень редкий пятый литерал, о котором мы поговорим при обсуждении комплексных чисел).

Целочисленные литералы — это последовательности цифр. Обычно это числа с основанием 10, но с помощью специального префикса можно задать и другое основание: префикс 0b означает двоичную систему счисления (с основанием 2), префикс 0o — восьмеричную (с основанием 8) и префикс 0x — шестнадцатеричную (с основанием 16). Префикс может быть записан как в верхнем, так и в нижнем регистре. Для обозначения восьмеричного литерала также можно использовать цифру 0 без какой-либо буквы после нее, но лучше никогда этого не делать, чтобы не было путаницы.

Go позволяет разбивать литерал на несколько частей с помощью символов подчеркивания, чтобы упростить чтение длинных целочисленных литералов. Это позволяет, например, отделять разряд тысяч в числах с основанием 10 (1_234). Эти символы подчеркивания не влияют на значение числа. Единственное ограничение состоит в том, что их нельзя размещать в начале или в конце числа и рядом друг с другом. Вы можете отделить друг от друга все разряды числа (1_2_3_4), но лучше не поступайте таким образом. Используйте символы подчеркивания для улучшения восприятия, например отделяя разряд тысяч в десятичных числах или разбивая двоичные, восьмеричные и шестнадцатеричные числа на группы из одного, двух или четырех байт.

Литералы чисел с плавающей запятой содержат десятичную запятую, отделя­ющую дробную часть значения. Они также могут содержать показатель степени, обозначаемый буквой e, за которой следует положительное или отрицательное число (например, 6,03e23). Их можно записывать в шестнадцатеричном виде, используя префикс 0x и букву p для обозначения показателя степени. Как и целочисленные литералы, литералы чисел с плавающей точкой можно форматировать с помощью символов подчеркивания.

Литералы рун представляют собой символы и заключаются в одинарные кавычки. В отличие от многих других языков в Go одинарные и двойные кавычки не являются взаимозаменяемыми. Литералы рун можно записывать в виде одиночных символов стандарта Unicode ('a'), восьмиразрядных восьмеричных чисел ('\141'), восьмиразрядных шестнадцатеричных чисел ('\x61'), 16-разрядных шестнадцатеричных чисел ('\u0061') и 32-разрядных кодов стандарта Unicode ('\U00000061'). Существует также ряд рунных литералов, экранированных символом обратной косой черты, из которых чаще всего используются символ новой строки ('\n'), символ табуляции ('\t'), одинарная кавычка ('\''), двойная кавычка ('\"') и обратная косая черта ('\\').

На практике рекомендуется использовать десятичную систему счисления для представления числовых литералов и, если это не объясняется контекстом, по возможности не применять шестнадцатеричные экранированные рунные литералы. В редких случаях может использоваться восьмеричное представление, главным образом для представления значений флагов разрешения стандарта POSIX (например, восьмеричное значение 0o777 для флагов rwxrwxrwx). Шестнадцатеричный и двоичный форматы представления иногда используются в битовых фильтрах или сетевых и инфраструктурных приложениях.

Существует два способа обозначения строковых литералов. В большинстве случаев следует использовать интерпретируемый строковый литерал, который создается с помощью двойных кавычек (например, "GreetingsandSalutations"). Такой литерал может содержать несколько рунных литералов в любом из допустимых форматов или не содержать их вовсе. Единственные символы, которые не могут здесь появиться, — символы обратной косой черты, новой строки и двойных кавычек. Если, допустим, нам нужно, чтобы второе слово фразы выводилось на новой строке и было заключено в кавычки, можно написать так: "Greetingsand\n\"Salutations\"".

Если же необходимо включить в строку символы обратной косой черты, двойных кавычек или новой строки, используйте необработанный строковый литерал. Такие литералы заключаются в символы обратной одинарной кавычки (`) и могут содержать любые символы, за исключением символа обратной кавычки. Используя необработанный строковый литерал, мы можем записать нашу фразу в двух строках следующим образом:

`Greetings and

"Salutations"`

Как вы увидите в подразделе «Явное преобразование типов» на с. 46, Go даже не позволяет складывать значения двух целочисленных переменных, если они объявлены как целые числа разной размерности. В то же время можно использовать целочисленный литерал в выражениях с плавающей запятой и даже присваивать целочисленный литерал самой переменной с плавающей запятой. Это объясняется тем, что литералы в Go представляют собой нетипизированные значения и потому могут взаимодействовать с любой переменной совместимого с литералами типа. В главе 7 вы увидите, что литералы можно использовать даже совместно с типами, определяемыми пользователем на основе простых типов. Однако это все, что позволяет сделать нетипизированный характер литералов: невозможно присвоить строковый литерал переменной числового типа и, наоборот, числовой литерал — строковой переменной либо присвоить литерал числа с плавающей точкой целочисленной переменной. Все подобные действия компилятор посчитает ошибкой.

Литералы являются нетипизированными по той причине, что Go ориентирован на практику. Нет смысла относить литерал к какому-либо типу, если разработчик еще не указал этот тип. При этом существуют ограничения в плане размера. Вы, конечно, можете записать числовой литерал, размер которого превышает размерность любого целочисленного типа, но получите ошибку времени компиляции, если попытаетесь присвоить переменной чрезмерно большое значение литерала, как, например, в случае присвоения литерала 1000 переменной типа byte.

Как вы увидите в разделе, посвященном присвоению значений переменным, иногда в Go-коде не производится явное указание типа. В таких случаях Go использует для литерала тип по умолчанию: если в выражении ничто не указывает на то, к какому типу следует отнести литерал, то этот литерал относится к типу по умолчанию. Мы еще коснемся отнесения литералов к типу по умолчанию при обсуждении различных встроенных типов.

Логические значения

Для представления логических значений используется тип bool. Переменные типа bool могут иметь одно из двух значений: true или false. Нулевым значением для типа bool является значение false:

var flag bool // переменной не присвоено значение, поэтому она равна false

var isAwesome = true

Надо сказать, что говорить о типах переменных достаточно сложно, не обсудив сначала способы их объявления, и наоборот. Мы сначала рассмотрим несколько примеров объявления переменных и обсудим их подробнее в разделе «var или :=» на с. 48.

Числовые типы

В Go много числовых типов (12, а также несколько специальных имен для этих типов), которые разделены на три категории. Если раньше вы использовали такой язык, как JavaScript, в котором лишь один числовой тип, то вас может немного удивить такое количество. При этом, на самом деле, одни типы используются довольно часто, а другие — крайне редко. Начнем с целочисленных типов, после чего рассмотрим типы чисел с плавающей запятой и редко используемые типы комплексных чисел.

Целочисленные типы

Язык Go предлагает типы для знаковых и беззнаковых целых чисел с размерностью от одного до восьми байт. Эти типы перечислены в табл. 2.1.

Таблица 2.1. Целочисленные типы языка Go

Имя типа

Диапазон значений

int8

От –128 до 127

int16

От –32 768 до 32 767

int32

От –2 147 483 648 до 2 147 483 647

int64

От –9 223 372 036 854 775 808 до 9 223 372 036 854 775 807

uint8

От 0 до 255

uint16

От 0 до 65 535

uint32

От 0 до 4 294 967 295

uint64

От 0 до 18 446 744 073 709 551 615

Нулевым значением для всех целочисленных типов, очевидно, является значение 0.

Специальные целочисленные типы

В Go предусмотрено несколько специальных имен для целочисленных типов. Так, byte — это псевдоним для типа uint8; значения типов byte и uint8 можно присваивать друг другу, сравнивать и использовать в одной математической операции. Однако вы редко увидите имя uint8 в Go-коде: вместо него принято применять имя byte.

Вторым специальным именем является имя int. На машинах с 32-разрядным процессором int означает 32-разрядное знаковое целое число, как и int32. На машинах с 64-разрядным процессором int означает 64-разрядное знаковое целое число, как и int64. Поскольку размерность типа int зависит от используемой платформы, вы получите ошибку времени компиляции, если попытаетесь присвоить друг другу, сравнить или применить в одной математической операции числа типов int и int32 (или типов int и int64) без преобразования типов (подробнее об этом будет рассказано в подразделе «Явное преобразование типов» на с. 46). Целочисленные литералы по умолчанию относятся к типу int.

В ряде нетипичных 64-разрядных процессорных архитектур в качестве типа int используются 32-разрядные знаковые целые числа. Go поддерживает три такие архитектуры: amd64p32, mips64p32 и mips64p32le.

Третьим специальным именем является имя uint. Для него действуют те же правила, что и в случае типа int, с тем лишь отличием, что это беззнаковый тип (то есть значение этого типа представляет собой либо 0, либо положительное число).

Существует еще два имени для целочисленных типов — rune и uintptr. Мы уже сталкивались с рунными литералами выше и подробно обсудим тип rune в подразделе «Пробуем использовать строки и руны» с. 46. Тип uintptr будет рассмотрен в главе 14.

Выбор подходящего целочисленного типа

Go предлагает больше целочисленных типов, чем многие другие языки. Такое богатство выбора может вызвать вопрос: когда лучше использовать каждый из этих типов? Здесь следует использовать три простых правила.

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

Если вы пишете библиотечную функцию, которая должна работать с любым целочисленным типом, напишите две функции, одна из которых будет использовать для параметров и переменных тип int64, а вторая — тип uint64. (О функциях и их параметрах мы подробно поговорим в главе 5.)

В данном случае идиоматический подход сводится к применению типов int64 и uint64 из-за того, что в языке Go нет (по крайней мере пока) универсальных функций и перегрузки. Без этих возможностей вам пришлось бы написать несколько функций для разных типов данных. Применение int64 и uint64 позволит написать код один раз, а затем пользоваться преобразованием типов для изменения данных по необходимости.

Этот подход применяется в стандартной библиотеке Go с функциями FormatInt/FormatUint и ParseInt/ParseUint из пакета strconv. Возможны и другие ситуации: например, в пакете math/bits размер целого числа имеет значение. В таких случаях необходимо написать отдельную функцию для каждого целочисленного типа.

Во всех остальных случаях следует использовать тип int.

Если нет необходимости в явном указании размерности или знака целочисленных значений из соображений производительности или обеспе­чения интеграции, используйте тип int. Пока не доказано иное, ис­пользование любого другого типа следует считать преждевременной оптимизацией.

Целочисленные операторы

Целые числа в Go поддерживают обычный набор арифметических операторов: +, , *, / и % (деление по модулю). Результатом целочисленного деления является целое число, и, чтобы получить в качестве результата число с плавающей запятой, необходимо использовать преобразование типов. Старайтесь не допускать деления целого числа на 0: это вызовет панику (подробнее о паниках будет рассказано в разделе «Функции panic и recover» на с. 216).

Округление при целочисленном делении в Go производится путем отбрасывания дробной части; подробности можно найти в разделе документации языка Go, посвященном арифметическим операторам (https://oreil.ly/zp3OJ).

Для изменения переменной можно сочетать любой из арифметических операторов с =: например, +=, –=, *=, /=, %=. Так, после выполнения следующего кода переменная x будет иметь значение 20:

var x int = 10

x *= 2

Для сравнения целых чисел можно использовать операторы ==, !=, >, >=, < и <=.

В Go также есть операторы побитовых манипуляций для целых чисел. Вы можете выполнять побитовый сдвиг влево и вправо с помощью операторов << и >> или применять битовые маски с помощью операторов & (логическое И), | (логическое ИЛИ), ^ (логическое исключающее ИЛИ) и &^ (логическое И-НЕ). Как и арифметические операторы, для изменения переменной все логические операторы могут быть объединены с = : &=, |=, ^=, &^=, <<=, >>=.

Типы чисел с плавающей запятой

В Go есть два типа чисел с плавающей запятой, которые представлены в табл. 2.2.

Таблица 2.2. Типы чисел с плавающей запятой, используемые в языке Go

Имя типа

Наибольшее абсолютное значение

Наименьшее (ненулевое) абсолютное значение

float32

3,40282346638528859811704183484516925440e+38

1,401298464324817070923729583289916131280e–45

float64

1,797693134862315708145274237317043567981e+308

4,940656458412465441765687928682213723651e–324

Как и для целочисленных типов, для типов чисел с плавающей точкой нулевым значением является 0.

Работа с числами с плавающей запятой в Go происходит практически так же, как в других языках. В Go используется формат представления таких чисел, основанный на спецификации IEEE 754, которая обеспечивает широкий диапазон и ограниченную степень точности. Выбрать подходящий тип достаточно просто: за исключением тех случаев, когда нужно обеспечить совместимость с имеющимся форматом, используется тип float64. Литералы чисел с плавающей запятой по умолчанию относятся к типу float64, поэтому самым простым решением будет всегда использовать тип float64. Это также позволяет уменьшить проблему точности чисел с плавающей запятой, связанную с тем, что точность типа float32 ограничивается только шестью или семью десятичными знаками после запятой. При этом не стоит волноваться о разнице в расходе памяти, за исключением того случая, когда профайлер явно укажет, что расход памяти является значительным источником проблем. (Тестирование и профайлинг мы подробно обсудим в главе 13.)

Более важный вопрос состоит в том, стоит ли вообще использовать число с плавающей запятой. В большинстве случаев ответ на него будет отрицательным. Как и в других языках, в Go числа с плавающей запятой охватывают огромный диапазон, но не могут поддерживать каждое значение в этом диапазоне, позволяя сохранить лишь ближайшее приближение. Поскольку числа с плавающей запятой не относятся к точным, их можно использовать только в ситуациях, когда допускаются приблизительные значения или известны правила их применения. Поэтому их практически не используют в компьютерной графике и научных расчетах.

Числа с плавающей запятой не могут обеспечить точное представление десятичных значений. Не используйте их для представления денежных сумм или других значений, которые требуют точного десятичного представления!

В случае чисел с плавающей запятой можно использовать все стандартн

...