Go (часто также golang) — компилируемый многопоточный язык программирования, разработанный внутри компании Google. Использует объектно-ориентированный (структурный) стиль с поддержкой функциональных элементов. Разработка Go началась в сентябре 2007 года, его непосредственным проектированием занимались Роберт Гризмер, Роб Пайк и Кен Томпсон, занимавшиеся до этого проектом разработки операционной системы Inferno. Официально язык был представлен в ноябре 2009 года. На данный момент поддержка официального компилятора, разрабатываемого создателями языка, осуществляется для операционных систем FreeBSD, OpenBSD, Linux, macOS, Windows, DragonFly BSD, Plan 9, Solaris, Android, AIX, Haiku OS. Также Go поддерживается набором компиляторов gcc, существует несколько независимых реализаций.

Название Название языка, выбранное компанией Google, практически совпадает с названием языка программирования Go!, созданного Ф. Джи. Маккейбом и К. Л. Кларком в 2003 году. Обсуждение названия ведётся на странице, посвящённой Go.

На домашней странице языка и вообще в интернет-публикациях часто используется альтернативное название — «golang».

Назначение, идеология Язык Go разрабатывался как язык программирования для создания высокоэффективных программ, работающих на современных распределённых системах и многоядерных процессорах. Он может рассматриваться как попытка создать замену языкам Си и C++ с учётом изменившихся компьютерных технологий и накопленного опыта разработки крупных систем. По словам Роба Пайка, «Go был разработан для решения реальных проблем, возникающих при разработке программного обеспечения в Google». В качестве основных таких проблем он называет:

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

Основными требованиями к языку стали: Ортогональность. Язык должен предоставлять небольшое число средств, не повторяющих функциональность друг друга. Простая и легкоразбираемая грамматика с минимумом ключевых слов. Простая работа с типами. Типизация должна обеспечивать безопасность, но не превращаться в бюрократию, лишь увеличивающую код. Отказ от иерархии типов, но с сохранением объектно-ориентированных возможностей. Отсутствие неявных преобразований. Сборка мусора. Встроенные средства распараллеливания, простые и эффективные. Поддержка строк, ассоциативных массивов и коммуникационных каналов. Чёткое разделение интерфейса и реализации. Эффективная система пакетов с явным указанием зависимостей, обеспечивающая быструю сборку.

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

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

Хотя для Go доступен и интерпретатор, практически в нём нет большой потребности, так как скорость компиляции достаточно высока для обеспечения интерактивной разработки.

Основные возможности языка Основные возможности языка Go: Go — язык со строгой статической типизацией. Доступен автоматический вывод типов, для пользовательских типов — «утиная типизация». Полноценная поддержка указателей, но без возможности применять к ним арифметические операции, в отличие от C/C++/D. Строковый тип со встроенной поддержкой юникода. Использование динамических массивов (срезов), хеш-таблиц (словарей), вариант цикла для обхода коллекции. Средства функционального программирования: неименованные функции, замыкания, передача функций в параметрах и возврат функциональных значений. Автоматическое управление памятью со сборщиком мусора. Средства объектно-ориентированного программирования ограничиваются интерфейсами. Полиморфное поведение обеспечивается реализацией интерфейсов типами. Реализация наследования отсутствует, но типы-структуры могут включать другие типы-структуры в себя. Средства параллельного программирования: встроенные в язык потоки (go routines), взаимодействие потоков через каналы и другие средства организации многопоточных программ. Достаточно лаконичный и простой синтаксис, основанный на Си, но существенно доработанный, с большим количеством синтаксического сахара.

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

Структурная запись обработчиков исключений сочтена провоцирующей на пропуск ошибок или неадекватную их обработку. К тому же поддержка исключений серьёзно усложняется в приложениях с параллельно работающими частями. Вместо неё предлагается проверка кодов возврата с использованием многозначных функций и специального интерфейса error, а также применение отложенных (deferred) функций для перехвата исключительных ситуаций. Наследование, как считают авторы, приводит к созданию кода с неявными зависимостями, избыточно сложного в поддержке. Аналогичные возможности, но без свойственных наследованию нежелательных эффектов, обеспечиваются поддержкой вложения типов и свободно определяемыми интерфейсами. Обобщённое программирование. Авторы воздержались от его включения в первую версию языка, поскольку, по их словам, предоставляемые им возможности не окупают требуемого усложнения компилятора и runtime-библиотек, а уже имеющиеся в языке средства (пустые интерфейсы, «утиная типизация» и рефлексия) позволяют создавать обобщённый код без специальных синтаксических механизмов. Тем не менее, обсуждается вопрос о включении таких средств в проектируемую вторую версию языка. Использование утверждений (assertion) было сочтено ненужным. Перегрузка методов и функций была исключена из соображений надёжности и эффективности компиляции: требование различного именования всех методов на одном уровне видимости устраняет необходимость сопоставлять списки параметров при компиляции вызовов функций и методов и исключает ошибочный вызов другого одноимённого метода; при этом сама возможность перегрузки есть не более чем синтаксический сахар. Ряд операций над массивами и срезами (например, вставка элемента в середину) не включён в язык, поскольку они достаточно затратны. Возможность их выполнения одной простой командой провоцировала бы программиста на создание неэффективного кода, отсутствие таких команд в языке, напротив, является стимулом для рассмотрения альтернативных решений. Поддержка отрицательных индексов,когда m[-1] означает последний элемент массива, m[-2] — второй с конца и так далее доступная в ряде популярных языков, может стать причиной труднообнаруживаемых ошибок: появление отрицательного индекса из-за ошибки в коде вместо того, чтобы привести к фатальному сбою, вызовет внешне корректное обращение не к тем элементам массива, что проявится только в неверных результатах и может быть обнаружено далеко не сразу. Принцип «любое выражение возвращает значение» провоцирует программиста на создание сложных, трудно воспринимаемых и чреватых неочевидными ошибками выражений (вроде копирования строки на Си командой из трёх слов: while (*ptr1++ = *ptr2++);). При этом современные технологии оптимизации обеспечат одинаковый объектный код и для экстремально сокращённого выражения, и для аналогичного ему фрагмента, написанного безо всяких ухищрений.

Синтаксис Синтаксис языка Go схож с синтаксисом языка Си, с отдельными элементами, заимствованными из Оберона и скриптовых языков.

Алфавит Go — регистрозависимый язык с полной поддержкой Юникода в строках и идентификаторах.

Идентификатор традиционно может быть любой непустой последовательностью, включающей буквы, цифры и знак подчёркивания, начинающийся с буквы и не совпадающий ни с одним из ключевых слов языка Go. При этом под «буквами» понимаются все символы Юникода, относящиеся к категориям «Lu» (буквы верхнего регистра), «Ll» (буквы нижнего регистра), «Lt» (заглавные буквы), «Lm» (буквы-модификаторы) или «Lo» (прочие буквы), под «цифрами» — все символы из категории «Nd» (числа, десятичные цифры). Таким образом, ничто не мешает использовать в идентификаторах, например, кириллицу.

Идентификаторы, различающиеся только регистром букв, являются различными. В языке существует ряд соглашений об использовании заглавных и строчных букв. В частности, в именах пакетов используются только строчные буквы. Все ключевые слова Go пишутся в нижнем регистре. Переменные, начинающиеся с заглавных букв, являются экспортируемыми (public), а начинающиеся со строчных букв — неэкспортируемыми (private).

В строковых литералах могут использоваться все символы Юникода без ограничений. Строки представляются как последовательности символов в кодировке UTF-8.

Пакеты Любая программа на Go включает один или несколько пакетов. Пакет, к которому относится файл исходного кода, задаётся описанием package в начале файла. Имена пакетов имеют те же ограничения, что и идентификаторы, но могут содержать буквы только нижнего регистра. Система пакетов go-среды имеет древовидную структуру, аналогичную дереву каталогов. Любые глобальные объекты (переменные, типы, интерфейсы, функции, методы, элементы структур и интерфейсов) доступны без ограничений в пакете, в котором они объявлены. Глобальные объекты, имена которых начинаются на заглавную букву, являются экспортируемыми.

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

package main /* Импорт */ import ( "fmt" // Стандартный пакет для форматированного вывода "database/sql" // Импорт вложенного пакета w "os" // Импорт с псевдонимом . "math" // Импорт без квалификации при использовании _ "gopkg.in/goracle.v2" // Пакет не имеет явных обращений в коде )

func main() { for _, arg := range w.Args { // Обращение к массиву Args, объявленному в пакете "os", через псевдоним fmt.Println(arg) // Обращение к функции Println(), объявленной в пакете "fmt", с именем пакета

var db *sql.DB = sql.Open(driver, dataSource) // Имена из вложенного пакета квалифицируются // только именем самого пакета (sql) x := Sin(1.0) // вызов math.Sin() - квалификация именем пакета math не нужна, // так как он импортирован без имени // Обращений к пакету "goracle.v2" в коде нет, но он будет импортирован. }

В ней перечисляются пути к импортируемым пакетам от каталога src в дереве исходных текстов, положение которого задаётся переменной среды GOPATH, а для стандартных пакетов достаточно указать имя. Перед строкой, идентифицирующей пакет, может быть указан псевдоним, тогда он будет использоваться в коде вместо имени пакета. Импортированные объекты доступны в импортирующем их файле с полной квалификацией вида «пакет.Объект». Если при импорте пакета вместо псевдонима указывается точка, то все экспортируемые им имена будут доступны без квалификации. Эта возможность используется некоторыми системными утилитами, однако её применение программистом не рекомендуется, так как явная квалификация обеспечивает защиту от коллизий имён и «незаметного» изменения поведения кода. Невозможно импортировать без квалификации два пакета, экспортирующих одно и то же имя.