Go — это статически типизированный , компилируемый высокоуровневый язык программирования общего назначения . Он был разработан в Google [12] в 2009 году Робертом Гриземером , Робом Пайком и Кеном Томпсоном . [4] Он синтаксически похож на C , но также имеет безопасность памяти , сборку мусора , структурную типизацию [7] и параллелизм в стиле CSP . [13] Его часто называют Golang из-за его бывшего доменного имени, , но его настоящее имя — Go. [14]golang.org
Существует два основных варианта реализации:
Сторонний компилятор исходного кода GopherJS [20] компилирует Go в JavaScript для разработки интерфейсных веб-приложений .
Go был разработан в Google в 2007 году для повышения производительности программирования в эпоху многоядерных сетевых машин и больших кодовых баз . [21] Разработчики хотели учесть критику других языков, используемых в Google, но сохранить их полезные характеристики: [22]
Его создатели были в первую очередь мотивированы общей неприязнью к C++ . [24] [25] [26]
Go был публично анонсирован в ноябре 2009 года, [27] а версия 1.0 была выпущена в марте 2012 года. [28] [29] Go широко используется в производстве в Google [30] и во многих других организациях и проектах с открытым исходным кодом.
Талисман Gopher был представлен в 2009 году для запуска языка с открытым исходным кодом . Дизайн, разработанный Рене Френч , был заимствован из рекламной акции WFMU 2000 года . [31]
В ноябре 2016 года шрифты Go и Go Mono были выпущены дизайнерами Чарльзом Бигелоу и Крисом Холмсом специально для использования в проекте Go. Go — гуманистический гротеск, напоминающий Lucida Grande , а Go Mono — моноширинный . Оба шрифта придерживаются набора символов WGL4 и были разработаны так, чтобы быть разборчивыми с большой высотой x и четкими формами букв . Оба шрифта Go и Go Mono придерживаются стандарта DIN 1450, имея перечеркнутый ноль, строчные буквы l
с хвостиком и заглавные буквы I
с засечками. [32] [33]
В апреле 2018 года оригинальный логотип был переработан дизайнером бренда Адамом Смитом. Новый логотип представляет собой современный стилизованный GO, наклоненный вправо с замыкающими обтекаемыми линиями. (Талисман Gopher остался прежним. [34] )
Отсутствие поддержки обобщенного программирования в начальных версиях Go вызвало значительную критику. [35] Разработчики выразили открытость для обобщенного программирования и отметили, что встроенные функции на самом деле были типово-обобщенными, но рассматривались как особые случаи; Пайк назвал это слабостью, которая может быть исправлена в какой-то момент. [36] Команда Google создала по крайней мере один компилятор для экспериментального диалекта Go с обобщениями, но не выпустила его. [37]
В августе 2018 года основные участники проекта Go опубликовали проекты проектов для универсального программирования и обработки ошибок и попросили пользователей присылать отзывы. [38] [39] Однако предложение по обработке ошибок в конечном итоге было отклонено. [40]
В июне 2020 года был опубликован новый черновой проектный документ [41] , который должен был добавить необходимый синтаксис в Go для объявления универсальных функций и типов. Инструмент перевода кода go2go был предоставлен, чтобы позволить пользователям попробовать новый синтаксис, вместе с версией онлайн-площадки Go Playground с поддержкой универсальных шаблонов. [42]
Дженерики были окончательно добавлены в Go в версии 1.18 15 марта 2022 года. [43]
Go 1 гарантирует совместимость [44] для спецификации языка и основных частей стандартной библиотеки. Все версии вплоть до текущего выпуска Go 1.23 [45] сохранили это обещание.
Go не следует SemVer ; вместо этого каждый основной релиз Go поддерживается до тех пор, пока не появятся два новых основных релиза. В отличие от большинства программ, Go называет вторую цифру в версии основной, т. е. является 1.x
x
основной версией. [46] Это потому, что Go не планирует никогда достичь версии 2.0, учитывая, что совместимость является одним из главных преимуществ языка. [47]
Go находится под влиянием C (особенно диалекта Plan 9 [48] [ неудачная проверка – см. обсуждение ] ), но с упором на большую простоту и безопасность. Он состоит из:
x := 0
var x int = 0;
var x = 0;
go get
) [51] и онлайн-документация по пакетам [52]select
операторСинтаксис Go включает изменения по сравнению с C, направленные на сохранение краткости и читаемости кода. Был введен комбинированный оператор объявления/инициализации, который позволяет программисту писать или , не указывая типы используемых переменных. Это контрастирует с C и .i := 3
s := "Hello, world!"
int i = 3;
const char *s = "Hello, world!";
Точка с запятой по-прежнему завершает операторы; [a] но подразумевается, когда наступает конец строки. [b]
Методы могут возвращать несколько значений, и возврат пары является общепринятым способом, которым метод сообщает об ошибке вызывающей стороне в Go. [c] Go добавляет литеральные синтаксисы для инициализации параметров структуры по имени и для инициализации карт и срезов . В качестве альтернативы трехоператорному циклу C выражения Go позволяют выполнять краткую итерацию по массивам, срезам, строкам, картам и каналам. [56]result, err
for
range
Go имеет ряд встроенных типов, включая числовые ( byte , int64 , float32 и т. д.), логические типы и байтовые строки ( string ). Строки неизменяемы; встроенные операторы и ключевые слова (а не функции) обеспечивают конкатенацию, сравнение и кодирование/декодирование UTF-8 . [57] Типы записей можно определить с помощью ключевого слова struct . [58]
Для каждого типа T и каждой неотрицательной целой константы n существует тип массива , обозначаемый [ n ] T ; массивы разной длины, таким образом, имеют разные типы. Динамические массивы доступны как «срезы», обозначаемые [] T для некоторого типа T . Они имеют длину и емкость, указывающие, когда необходимо выделить новую память для расширения массива. Несколько срезов могут совместно использовать свою базовую память. [36] [59] [60]
Указатели доступны для всех типов, а указатель на тип T обозначается * T . Получение адреса и косвенность используют операторы & и * , как в C, или происходят неявно через вызов метода или синтаксис доступа к атрибуту. [61] [62] Арифметики указателей нет, [d] за исключением специального типа unsafe.Pointer в стандартной библиотеке. [63]
Для пары типов K , V тип map[ K ] V является типом, отображающим ключи типа K в значения типа V , хотя спецификация языка программирования Go не дает никаких гарантий производительности или требований к реализации для типов map. Хэш-таблицы встроены в язык со специальным синтаксисом и встроенными функциями. chan T — это канал , позволяющий отправлять значения типа T между параллельными процессами Go. [64]
Помимо поддержки интерфейсов, система типов Go является номинальной : ключевое слово type может использоваться для определения нового именованного типа , который отличается от других именованных типов, имеющих ту же структуру (в случае struct — те же члены в том же порядке). Некоторые преобразования между типами (например, между различными целочисленными типами) предопределены, и добавление нового типа может определять дополнительные преобразования, но преобразования между именованными типами всегда должны вызываться явно. [65] Например, ключевое слово type может использоваться для определения типа для адресов IPv4 на основе 32-битных беззнаковых целых чисел следующим образом:
тип ipv4addr uint32
При таком определении типа ipv4addr(x) интерпретирует значение uint32 x как IP-адрес. Простое присвоение x переменной типа ipv4addr является ошибкой типа. [66]
Константные выражения могут быть типизированными или «нетипизированными»; им присваивается тип при назначении типизированной переменной, если представляемое ими значение проходит проверку во время компиляции. [67]
Типы функций обозначаются ключевым словом func ; они принимают ноль или более параметров и возвращают ноль или более значений, все из которых типизированы. Параметр и возвращаемые значения определяют тип функции; таким образом, func(string, int32) (int, error) — это тип функций, которые принимают строку и 32-битное знаковое целое число и возвращают знаковое целое число (ширины по умолчанию) и значение встроенного типа интерфейса error . [68]
Любой именованный тип имеет набор методов, связанных с ним. Пример IP-адреса выше можно расширить с помощью метода для проверки того, является ли его значение известным стандартом:
// ZeroBroadcast сообщает, является ли addr 255.255.255.255. func ( addr ipv4addr ) ZeroBroadcast () bool { return addr == 0xFFFFFFFF }
Из-за номинальной типизации это определение метода добавляет метод к ipv4addr , но не к uint32 . Хотя методы имеют специальное определение и синтаксис вызова, отдельного типа метода нет. [69]
Go предоставляет две функции, которые заменяют наследование классов . [ необходима ссылка ]
Первый — это встраивание , которое можно рассматривать как автоматизированную форму композиции . [70]
Вторым являются его интерфейсы , которые обеспечивают полиморфизм времени выполнения . [71] : 266 Интерфейсы являются классом типов и предоставляют ограниченную форму структурной типизации в иной номинальной системе типов Go. Объект, который имеет тип интерфейса, также имеет другой тип, во многом подобно объектам C++, которые одновременно являются базовым и производным классом. Интерфейсы Go были разработаны по протоколам из языка программирования Smalltalk. [72] Во многих источниках при описании интерфейсов Go используется термин «утиная типизация» . [73] [74] Хотя термин «утиная типизация» не определен точно и, следовательно, не является неправильным, он обычно подразумевает, что соответствие типам статически не проверяется. Поскольку соответствие интерфейсу Go статически проверяется компилятором Go (за исключением случаев выполнения утверждения типа), авторы Go предпочитают термин « структурная типизация» . [75]
Определение типа интерфейса перечисляет требуемые методы по имени и типу. Любой объект типа T, для которого существуют функции, соответствующие всем требуемым методам типа интерфейса I, также является объектом типа I. Определение типа T не должно (и не может) идентифицировать тип I. Например, если Shape , Square и Circle определены как
импорт "математика" тип интерфейса Shape { Area () float64 } type Square struct { // Примечание: нет объявления "implements" side float64 } func ( sq Square ) Area () float64 { return кв . сторона * кв . сторона } type Circle struct { // Здесь нет объявления "implements" radius float64 } func ( c Circle ) Area ( ) float64 { return math.Pi * math.Pow ( c.radius , 2 ) }
тогда и Square , и Circle неявно являются Shape и могут быть назначены переменной типа Shape . [71] : 263–268 На формальном языке система интерфейсов Go обеспечивает структурную, а не номинальную типизацию. Интерфейсы могут встраивать другие интерфейсы с эффектом создания комбинированного интерфейса, который удовлетворяется именно теми типами, которые реализуют встроенный интерфейс, и любыми методами, которые добавляет новый определенный интерфейс. [71] : 270
Стандартная библиотека Go использует интерфейсы для обеспечения универсальности в нескольких местах, включая систему ввода/вывода, основанную на концепциях Reader и Writer . [71] : 282–283
Помимо вызова методов через интерфейсы, Go позволяет преобразовывать значения интерфейсов в другие типы с проверкой типа во время выполнения. Конструкции языка для этого — это утверждение типа [76] , которое проверяет единственный потенциальный тип:
var shp Shape = Square { 5 } square , ok := shp .( Square ) // Проверяет тип Square на shp, должно работать if ok { fmt . Printf ( "%#v\n" , square ) } else { fmt . Println ( "Невозможно напечатать форму как Square" ) }
и переключатель типа , [77] который проверяет по нескольким типам: [ необходима ссылка ]
func ( sq Square ) Diagonal ( ) float64 { return sq.side * math.Sqrt2 } func ( c Circle ) Dimeter ( ) float64 { return 2 * c.radius } func LongestContainedLine ( shp Shape ) float64 { switch v := shp .( type ) { case Square : return v . Diagonal () // Или, с утверждением типа, shp.(Square).Diagonal() case Circle : return v . Diameter () // Или, с утверждением типа, shp.(Circle).Diameter() default : return 0 // На практике это должно обрабатываться с ошибками } }
Пустой интерфейс является важным базовым случаем, поскольку он может ссылаться на элемент любого конкретного типа. Он похож на класс Object в Java или C# и удовлетворяется любым типом, включая встроенные типы, такие как int . [71] : 284 Код, использующий пустой интерфейс, не может просто вызывать методы (или встроенные операторы) для объекта, на который ссылаются, но он может сохранять значение , пытаться преобразовать его в более полезный тип с помощью утверждения типа или переключения типа или проверять его с помощью пакета Go . [78] Поскольку может ссылаться на любое значение, это ограниченный способ обойти ограничения статической типизации, как в C, но с дополнительными проверками типов во время выполнения. [ необходима цитата ]interface{}
interface{}
reflect
interface{}
void*
Тип может использоваться для моделирования структурированных данных любой произвольной схемы в Go, например, данных JSON или YAML , представляя их как (карту строки в пустой интерфейс). Это рекурсивно описывает данные в форме словаря со строковыми ключами и значениями любого типа. [79]interface{}
map[string]interface{}
Значения интерфейса реализуются с использованием указателя на данные и второго указателя на информацию о типе времени выполнения. [80] Как и некоторые другие типы, реализованные с использованием указателей в Go, значения интерфейса являются nil
неинициализированными. [81]
Начиная с версии 1.18, Go поддерживает универсальный код с использованием параметризованных типов. [82]
Функции и типы теперь могут быть универсальными с использованием параметров типа. Эти параметры типа указываются в квадратных скобках, сразу после имени функции или типа. [83] Компилятор преобразует универсальную функцию или тип в неуниверсальный, заменяя аргументы типа на предоставленные параметры типа, либо явно пользователем, либо выводом типа компилятором. [84] Этот процесс преобразования называется инстанцированием типа. [85]
Интерфейсы теперь могут определять набор типов (известный как набор типов) с помощью |
оператора (Union), а также набор методов. Эти изменения были сделаны для поддержки ограничений типов в коде обобщений. Для обобщенной функции или типа ограничение можно рассматривать как тип аргумента типа: метатип. Этот новый ~T
синтаксис будет первым использованием ~
в качестве токена в Go. ~T
означает набор всех типов, базовым типом которых является T
. [86]
тип Числовой интерфейс { ~ int | ~ float64 | ~ float32 | ~ int32 | ~ int64 } func Add [ T Number ]( nums ... T ) T { var sum T for _ , v := range nums { sum += v } return sum } func main () { add := Add [ int ] // Создание экземпляра типа println ( add ( 1 , 2 , 3 , 4 , 5 )) // 15 res := Add ( 1.1 , 2.2 , 3.3 , 4.4 , 5.5 ) // Вывод типа println ( res ) // +1.650000e+001 }
Go использует iota
ключевое слово для создания перечисляемых констант. [87]
тип ByteSize float64 const ( _ = iota // игнорировать первое значение, присваивая его пустому идентификатору KB ByteSize = 1 << ( 10 * iota ) MB GB )
В системе пакетов Go каждый пакет имеет путь (например, "compress/bzip2"
или "golang.org/x/net/html"
) и имя (например, bzip2
или html
). Ссылки на определения других пакетов всегда должны начинаться с имени другого пакета, и доступны только заглавныеio.Reader
имена из других пакетов: является публичным, но bzip2.reader
не является. [88] Команда go get
может извлекать пакеты, хранящиеся в удаленном репозитории [89], и разработчикам рекомендуется разрабатывать пакеты внутри базового пути, соответствующего исходному репозиторию (например, example.com/user_name/package_name), чтобы снизить вероятность конфликта имен с будущими дополнениями к стандартной библиотеке или другим внешним библиотекам. [90]
Язык Go имеет встроенные возможности, а также поддержку библиотек для написания параллельных программ . Параллелизм относится не только к параллелизму ЦП, но и к асинхронности : позволяя медленным операциям, таким как чтение базы данных или сети, выполняться, пока программа выполняет другую работу, как это часто бывает в серверах, основанных на событиях. [91]
Первичная конструкция параллелизма — это goroutine , тип зеленого потока . [92] : 280–281 Вызов функции с префиксом в виде go
ключевого слова запускает функцию в новой goroutine. Спецификация языка не определяет, как должны быть реализованы goroutines, но текущие реализации мультиплексируют goroutines процесса Go на меньший набор потоков операционной системы , аналогично планированию, выполняемому в Erlang . [93] : 10
Хотя стандартный пакет библиотеки, включающий большинство классических структур управления параллелизмом (блокировки мьютексов и т. д.), доступен, [93] : 151–152 идиоматические параллельные программы вместо этого предпочитают каналы , которые отправляют сообщения между горутинами. [94] Необязательные буферы хранят сообщения в порядке FIFO [95] : 43 и позволяют отправлять горутинам продолжать работу до получения их сообщений. [92] : 233
Каналы типизированы, так что канал типа chan T может использоваться только для передачи сообщений типа T . Для работы с ними используется специальный синтаксис; <-ch — это выражение, которое блокирует выполняющуюся goroutine до тех пор, пока по каналу ch не поступит значение , в то время как ch <- x отправляет значение x (возможно, блокируя до тех пор, пока другая goroutine не получит значение). Встроенный switch -like оператор select может использоваться для реализации неблокируемой связи по нескольким каналам; см. пример ниже. Go имеет модель памяти, описывающую, как goroutines должны использовать каналы или другие операции для безопасного обмена данными. [96]
Существование каналов само по себе не отличает Go от параллельных языков в стиле модели акторов , таких как Erlang, где сообщения адресуются непосредственно акторам (соответствующим горутинам). В модели акторов каналы сами являются акторами, поэтому обращение к каналу означает просто обращение к актору. Стиль акторов можно смоделировать в Go, поддерживая однозначное соответствие между горутинами и каналами, но язык позволяет нескольким горутинам совместно использовать канал или одной горутине отправлять и получать данные по нескольким каналам. [93] : 147
С помощью этих инструментов можно создавать параллельные конструкции, такие как рабочие пулы, конвейеры (в которых, скажем, файл распаковывается и анализируется по мере загрузки), фоновые вызовы с тайм-аутом, «разветвленные» параллельные вызовы к набору служб и другие. [97] Каналы также нашли применение, выходящее за рамки обычного понятия межпроцессного взаимодействия, например, выступая в качестве списка параллельно-безопасных переработанных буферов, [98] реализуя сопрограммы (что помогло вдохновить на название goroutine ), [99] и реализуя итераторы . [100]
Структурные соглашения Go, связанные с параллелизмом ( каналы и альтернативные входы каналов), вытекают из модели последовательных процессов Тони Хоара . В отличие от предыдущих языков параллельного программирования, таких как Occam или Limbo (язык, над которым работал соавтор Go Роб Пайк), [101] Go не предоставляет никаких встроенных понятий безопасного или проверяемого параллелизма. [102] Хотя модель коммуникационных процессов является предпочтительной в Go, она не единственная: все горутины в программе совместно используют одно адресное пространство. Это означает, что изменяемые объекты и указатели могут совместно использоваться между горутинами; см. § Отсутствие безопасности гонки данных ниже.
Хотя параллелизмные функции Go не нацелены в первую очередь на параллельную обработку , [91] их можно использовать для программирования многопроцессорных машин с общей памятью . Были проведены различные исследования эффективности этого подхода. [103] В одном из этих исследований сравнивался размер (в строках кода ) и скорость программ, написанных опытным программистом, не знакомым с языком, и исправления этих программ экспертом Go (из команды разработчиков Google), делая то же самое для Chapel , Cilk и Intel TBB . Исследование показало, что неэксперты имели тенденцию писать алгоритмы «разделяй и властвуй» с одним оператором go на рекурсию, в то время как эксперты писали программы «распределяй-работай-синхронизируй», используя одну горутину на ядро процессора. Программы экспертов обычно были быстрее, но и длиннее. [104]
Подход Go к параллелизму можно обобщить как «не общайтесь, разделяя память; разделяйте память, общаясь». [105] Нет никаких ограничений на то, как горутины получают доступ к общим данным, что делает возможными гонки данных . В частности, если программа явно не синхронизируется через каналы или другими способами, записи из одной горутины могут быть частично, полностью или вообще не видны другой, часто без каких-либо гарантий относительно порядка записей. [102] Более того, внутренние структуры данных Go , такие как значения интерфейсов, заголовки срезов, хэш-таблицы и заголовки строк, не защищены от гонок данных, поэтому безопасность типов и памяти может быть нарушена в многопоточных программах, которые изменяют общие экземпляры этих типов без синхронизации. [106] [107] Таким образом, вместо поддержки языка безопасное параллельное программирование опирается на соглашения; например, Чисналл рекомендует идиому под названием «псевдонимы xor mutable», означающую, что передача изменяемого значения (или указателя) по каналу сигнализирует о передаче права собственности на значение его получателю. [93] : 155 В цепочке инструментов gc есть дополнительный детектор гонки данных, который может проверять несинхронизированный доступ к общей памяти во время выполнения, начиная с версии 1.1, [108] кроме того, детектор гонки «лучшее усилие» также включен по умолчанию, начиная с версии 1.6 среды выполнения gc для доступа к map
типу данных. [109]
Компоновщик в цепочке инструментов gc по умолчанию создает статически связанные двоичные файлы; поэтому все двоичные файлы Go включают среду выполнения Go. [110] [111]
Go намеренно опускает некоторые функции, общие для других языков, включая (реализацию) наследование , утверждения , [e] арифметику указателей , [d] неявные преобразования типов , немаркированные объединения , [f] и маркированные объединения . [g] Разработчики добавили только те возможности, с которыми согласились все три. [114]
Из пропущенных языковых возможностей разработчики явно выступают против утверждений и арифметики указателей, защищая при этом выбор пропустить наследование типов как дающий более полезный язык, поощряя вместо этого использование интерфейсов для достижения динамической диспетчеризации [h] и композиции для повторного использования кода. Композиция и делегирование фактически в значительной степени автоматизированы с помощью встраивания структур ; по словам исследователей Шмагера и др. , эта функция «имеет много недостатков наследования: она влияет на открытый интерфейс объектов, она не является мелкозернистой (т. е. нет контроля на уровне методов над встраиванием), методы встраиваемых объектов не могут быть скрыты, и она статична», что делает «неочевидным», будут ли программисты злоупотреблять ею в той степени, в которой программисты на других языках, как известно, злоупотребляют наследованием. [70]
Обработка исключений изначально была опущена в Go из-за отсутствия «дизайна, который дает значение, пропорциональное сложности». [115] Механизм паники / восстановления , подобный исключению , который избегает обычной структуры управления, был предложен [116] и выпущен в снимке 30 марта 2010 года. [117] Авторы Go советуют использовать его для неустранимых ошибок, таких как те, которые должны остановить всю программу или запрос сервера, или в качестве сокращения для распространения ошибок вверх по стеку внутри пакета. [118] [119] За пределами границ пакета Go включает канонический тип ошибки, и возврат нескольких значений с использованием этого типа является стандартной идиомой. [4]try-catch
Авторы Go приложили значительные усилия, чтобы повлиять на стиль программ Go:
gofmt
. Он использует табуляции для отступов и пробелы для выравнивания. Выравнивание предполагает, что редактор использует шрифт фиксированной ширины. [120] golint
выполняет дополнительные проверки стиля автоматически, но был объявлен устаревшим и архивирован разработчиками Go. [121]godoc
), [122] тестирование ( go test
), сборка ( go build
), управление пакетами ( go get
) и т. д.map
try
finally
Основной дистрибутив Go включает в себя инструменты для сборки , тестирования и анализа кода:
go build
, который собирает двоичные файлы Go, используя только информацию из исходных файлов, без отдельных make-файловgo test
, для модульного тестирования и микротестов, а также фаззингаgo fmt
, для форматирования кодаgo install
, для извлечения и установки удаленных пакетовgo vet
, статический анализатор, ищущий потенциальные ошибки в кодеgo run
, ярлык для сборки и выполнения кодаgodoc
, для отображения документации или ее обслуживания через HTTPgorename
, для переименования переменных, функций и т. д. безопасным для типов способомgo generate
, стандартный способ вызова генераторов кодаgo mod
, для создания нового модуля, добавления зависимостей, обновления зависимостей и т. д.Он также включает поддержку профилирования и отладки , возможности фаззинга для обнаружения ошибок, инструментарий времени выполнения (например, для отслеживания пауз при сборке мусора ) и детектор гонки данных .
Еще один инструмент, поддерживаемый командой Go, но не включенный в дистрибутивы Go gopls
, — это языковой сервер, который предоставляет такие функции IDE , как интеллектуальное завершение кода для редакторов, совместимых с протоколом языкового сервера . [128]
Экосистема сторонних инструментов дополняет стандартный дистрибутив, например gocode
, , который обеспечивает автодополнение кода во многих текстовых редакторах, goimports
, который автоматически добавляет/удаляет импорт пакетов по мере необходимости, и errcheck
, который обнаруживает код, который может непреднамеренно игнорировать ошибки.
основной пакет импорт "фмт" func main () { fmt . Println ( "привет мир" ) }
где "fmt" - это пакет для форматированного ввода-вывода , аналогичный файлу ввода-вывода C в языке C. [129]
Следующая простая программа демонстрирует возможности параллелизма Go для реализации асинхронной программы. Она запускает два легких потока («goroutines»): один ждет, пока пользователь введет текст, а другой реализует тайм-аут. Оператор select ждет, пока любой из этих goroutines отправит сообщение в основную процедуру, и действует на первое полученное сообщение (пример адаптирован из книги Дэвида Чисналла). [93] : 152
основной пакет импорт ( "fmt" "время" ) func readword ( ch chan string ) { fmt . Println ( "Введите слово, затем нажмите Enter." ) var word string fmt . Scanf ( "%s" , & word ) ch <- word } func timeout ( t chan bool ) { time.Sleep ( 5 * time.Second ) t < - false } func main () { t := make ( chan bool ) go timeout ( t ) ch := make ( chan string ) go readword ( ch ) select { case word := <- ch : fmt . Println ( "Получено" , word ) case <- t : fmt . Println ( "Время ожидания истекло." ) } }
Пакет тестирования обеспечивает поддержку автоматизированного тестирования пакетов go. [130] Пример целевой функции:
func ExtractUsername ( email string ) string { at := strings.Index ( email , " @" ) return email [ : at ] }
Тестовый код (обратите внимание, что ключевое слово assert отсутствует в Go; тесты находятся в <filename>_test.go в том же пакете):
импорт ( "тестирование" ) func TestExtractUsername ( t * testing.T ) { t . Run ( "withoutDot" , func ( t * testing.T ) { username := ExtractUsername ( "[email protected]" ) if username != "r" { t . Fatalf ( " Got : % v\ n " , username ) } }) t . Run ( "withDot" , func ( t * testing . T ) { имя пользователя := ExtractUsername ( "[email protected]" ) если имя пользователя != "jonh.smith" { t . Fatalf ( "Получил: %v\n" , имя пользователя ) } }) }
Возможно параллельное проведение тестов.
Пакет net/http обеспечивает поддержку создания веб-приложений.
В этом примере при посещении localhost:8080 будет отображаться сообщение «Hello world!».
основной пакет импорт ( "fmt" "log" "net/http" ) func helloFunc ( w http.ResponseWriter , r * http.Request ) { fmt.Fprintf ( w , " Привет , мир ! " ) } func main ( ) { http.HandleFunc ( "/ " , helloFunc ) log.Fatal ( http.ListenAndServe ( " : 8080 " , nil ) ) }
Go нашел широкое применение в различных областях благодаря своей надежной стандартной библиотеке и простоте использования. [131]
Популярные приложения включают в себя: Caddy , веб-сервер, который автоматизирует процесс настройки HTTPS, [132] Docker , который предоставляет платформу для контейнеризации, направленную на упрощение сложностей разработки и развертывания программного обеспечения, [133] Kubernetes , который автоматизирует развертывание, масштабирование и управление контейнеризированными приложениями, [134] CockroachDB , распределенную базу данных SQL, разработанную для масштабируемости и строгой согласованности, [135] и Hugo , статический генератор сайтов, который отдает приоритет скорости и гибкости, позволяя разработчикам эффективно создавать веб-сайты. [136]
Система интерфейса и преднамеренный отказ от наследования были высоко оценены Микеле Симионато, который сравнил эти характеристики с характеристиками стандартного ML , назвав это «позором, что ни один популярный язык не пошел [по этому] конкретному пути». [137]
Дэйв Астелс из Engine Yard написал в 2009 году: [138]
Go чрезвычайно прост в освоении. Существует минимальное количество основных концепций языка, а синтаксис чистый и разработан так, чтобы быть понятным и недвусмысленным. Go все еще экспериментальный и все еще немного грубый по краям.
Go был назван языком программирования года индексом сообщества программирования TIOBE в свой первый год, 2009, за больший 12-месячный рост популярности (всего за 2 месяца после его введения в ноябре), чем любой другой язык в том году, и достиг 13-го места к январю 2010 года, [139] превзойдя такие устоявшиеся языки, как Pascal . К июню 2015 года его рейтинг упал ниже 50-го места в индексе, поместив его ниже COBOL и Fortran . [140] Но по состоянию на январь 2017 года его рейтинг резко вырос до 13-го места, что указывает на значительный рост популярности и принятия. Go снова был удостоен награды TIOBE Programming Language of the Year в 2016 году. [141]
Брюс Экель заявил: [142]
Сложность C++ (еще больше сложности было добавлено в новом C++) и вызванное этим влияние на производительность больше не оправданы. Все эти обручи, через которые приходилось прыгать программисту C++, чтобы использовать совместимый с C язык, больше не имеют смысла — это просто пустая трата времени и усилий. Go гораздо более осмыслен для класса задач, которые изначально предназначался решать C++.
Оценка языка и его реализации gc в сравнении с C++ ( GCC ), Java и Scala, проведенная инженером Google в 2011 году, показала:
Go предлагает интересные языковые возможности, которые также позволяют использовать краткую и стандартизированную нотацию. Компиляторы для этого языка все еще незрелые, что отражается как на производительности, так и на размерах двоичных файлов.
— Р. Хундт [143]
Оценка получила опровержение от команды разработчиков Go. Ян Лэнс Тейлор, который улучшил код Go для статьи Хундта, не знал о намерении опубликовать свой код и говорит, что его версия «никогда не была предназначена для того, чтобы быть примером идиоматического или эффективного Go»; Расс Кокс затем оптимизировал код Go, а также код C++, и добился того, что код Go работал почти так же быстро, как версия C++, и более чем на порядок быстрее, чем код в статье. [144]
10 ноября 2009 года, в день общего выпуска языка, Фрэнсис Маккейб, разработчик языка программирования Go! (обратите внимание на восклицательный знак), попросил изменить название языка Google, чтобы избежать путаницы с его языком, на разработку которого он потратил 10 лет. [151] Маккейб выразил опасения, что «большой парень» в конечном итоге раздавит его, и это беспокойство нашло отклик у более чем 120 разработчиков, которые прокомментировали официальную ветку проблем Google, заявив, что им следует изменить название, а некоторые [152] даже заявили, что проблема противоречит девизу Google: « Не будь злым » . [153]
12 октября 2010 года поданное публичное сообщение об ошибке было закрыто разработчиком Google Рассом Коксом (@rsc) с пользовательским статусом «Неудачно» и следующим комментарием:
«Существует множество компьютерных продуктов и услуг под названием Go. За 11 месяцев с момента нашего выпуска путаница между двумя языками была минимальной». [153]
Go поддерживает функции первого класса, функции высшего порядка, определяемые пользователем типы функций, литералы функций, замыкания и множественные возвращаемые значения. Этот богатый набор функций поддерживает функциональный стиль программирования на строго типизированном языке.
Хотя Go имеет типы и методы и допускает объектно-ориентированный стиль программирования, иерархии типов нет.
является объектно-ориентированным, но не в обычном смысле.
Go используется структурная типизация, а не утиная типизация. Полное соответствие интерфейсу проверяется и требуется.
называется Go.
и среда выполнения теперь реализованы на Go и ассемблере, без C.
gccgo, компилятор GNU для языка программирования Go
— это компилятор Go на основе LLVM.
выпустила версию 1 своего языка программирования Go, амбициозную попытку превзойти гигантов мира программирования низкого уровня, таких как C и C++.
Go правило о видимости информации простое: если имя (типа верхнего уровня, функции, метода, константы или переменной, поля структуры или метода) написано с заглавной буквы, пользователи пакета могут его увидеть. В противном случае имя и, следовательно, именуемая вещь видны только внутри пакета, в котором они объявлены.
Пакетам из стандартной библиотеки даны короткие пути импорта, такие как "fmt" и "net/http". Для ваших собственных пакетов вы должны выбрать базовый путь, который вряд ли будет конфликтовать с будущими дополнениями к стандартной библиотеке или другим внешним библиотекам. Если вы храните свой код в исходном репозитории где-то, то вы должны использовать корень этого исходного репозитория в качестве базового пути. Например, если у вас есть учетная запись Example на example.com/user, это должен быть ваш базовый путь
Преимущества единого, программно предписанного формата для всех программ Go значительно перевешивают любые предполагаемые недостатки конкретного стиля.
Например, около 58% ошибок блокировки вызваны передачей сообщений. Помимо нарушения правил использования каналов Go (например, ожидание на канале, на который никто не отправляет данные или который не закрывается), многие ошибки параллелизма вызваны смешанным использованием передачи сообщений и других новых семантик и новых библиотек в Go, которые можно легко пропустить, но трудно обнаружить.