В программировании постоянно разрабатываются новые языки. В каждом из них разработчики стремятся расширять возможности предыдущих технологий. Одним из таких примеров является язык Go, или Golang (Google language). Разработанный в компании Google, Golang был создан с целью объединить черты своих предшественников и предложить программистам новый инструмент для создания приложений. Когда создатели Golang приступили к разработке, они учитывали опыт различных языков, таких как C, C++, Java и Python.
Наша команда активно использует Golang для работы, например с Terraform-провайдером, поэтому мы решили разобрать его особенности подробнее. В этой статье мы рассмотрим историю языка, почему он стал таким востребованным среди разработчиков, разберем, какие черты заимствованы от C и других языков, а также дадим небольшую подборку материалов для самостоятельного изучения.
C и C++
Начнем с истоков. Как уже было сказано многие языки программирования появляются из других языков, как бы парадоксально это не звучало. Объединяя преимущества и убирая недостатки одних – и создаются новые инструменты. Так, язык программирования C был разработан в начале 1970-х годов в лаборатории Bell Labs (Bell Telephone Laboratories) компании AT&T (American Telephone and Telegraph Company). Его создателями являются Деннис Ритчи и Кен Томпсон.
В начале 1970-х годов в Bell Labs для разработки операционной системы UNIX был создан язык программирования «B», который был расширением языка BCPL. Однако «B» имел некоторые недостатки. В связи с этим, Деннис Ритчи и Кен Томпсон начали разрабатывать новый язык, в который внесли множество улучшений и новых функций. Первый прототип языка получил название NB (New B). Позже язык был переименован в «С» в отношении его предшественника «B». Этот выбор имени имел и символический смысл – «С» был «следующим» языком после языка «B». A, B, C…ну, вы поняли.
Язык C стал популярным среди разработчиков и быстро распространился, прежде всего благодаря тому, что с его помощью была написана операционная система UNIX. C стал стандартным языком программирования для разработки системного и прикладного программного обеспечения.
В 1978 году была выпущена первая версия стандарта ANSI C (American National Standards Institute C), что стало ключевым моментом в истории развития языка. В последующие десятилетия язык C оставался одним из самых популярных и широко используемых, став основой для множества других языков, таких как C++.
Перейдем к C++, до 2007 года он был одним из самых популярных языков программирования. Создан он был Бьёрном Страуструпом с целью разработки такого инструмента, который позволял бы ему более эффективно писать программы для UNIX.
Страуструп хотел расширить возможности C, добавив в него некоторые возможности объектно-ориентированного программирования (ООП), чтобы сделать код более структурированным и упорядоченным. В 1983 году он создал прототип языка, который назвал «C with Classes» (C с классами), что стало первым шагом к созданию C++. Окончательная же версия языка была выпущена в 1985 году, где уже были реализованы основные концепции: классы, наследование, инкапсуляция и полиморфизм.
Google и Go
В 2007 году Google столкнулся с проблемами в создании крупномасштабных приложений. Так как это крупная компания, она, конечно, имеет большое аппаратное и программное обеспечение. Поэтому проблемы, связанные с многоядерными процессорами, сетевыми системами, массивными вычислительными кластерами и моделью веб-программирования, скорее просто обрабатывались, чем действительно решались.
Google использовал комбинацию языков C++, Python и Java, но ни один из них не обеспечивал той эффективности, простоты и масштабируемости, в которых нуждался Google. Если быть точнее, то серверная часть была написана на C++, а для других использовались Java и Python. Тысячи инженеров работают в Google над кодом, поэтому изменения происходят здесь на всех уровнях дерева. Большая специализированная распределенная система сборки делает разработку в таком масштабе осуществимой, но она все равно остается большой.
Все это работает на миллионах машин, которые рассматриваются как небольшое количество независимых вычислительных кластеров, объединенных в сеть. Короче говоря, разработка в Google могла быть довольно медленной.
В принципе из-за этого и была собрана группа из разработчиков, в которую вошли Роберт Гризмер, Роб Пайк и Кен Томпсон, сотрудники Google. Они должны были разработать такой язык, который сочетал бы в себе простоту и эффективность C и C++, с возможностями параллельного программирования и современным подходом к разработке.
Цель проекта – создать язык, который был бы таким же быстрым, как C++, простым в написании, как Python, и масштабируемым, как Java.
Разработка началась в сентябре 2007 года. По мере развития, конечно, к ним присоединялись и другие программисты. В январе 2008 года началась работа над исходным компилятором.
Первая версия Go была выпущена в ноябре 2009 года, и с тех пор она претерпела несколько крупных релизов. Потребовалось еще несколько лет, чтобы выпустить первую стабильную версию Go в марте 2012 года. Подробнее о выпуске можно прочитать в примечаниях.
С момента своего первого выпуска Golang сильно изменялся, особенно в синтаксисе и семантике языка. Google попытался удалить следы C из языка, сделав его структуру еще более простой в использовании. В результате Golang стал более дружелюбным к разработчикам, которые не имеют опыта работы с другими языками программирования.
Самый значимый релиз был представлен в августе 2015 года – Golang 1.5 (примечания к выпуску), где инструментарий компилятора был полностью преобразован с C на Go. На этом этапе Golang принял тот вид, к которому стремились его авторы. Дальше он уже переходил в фазу доработки и создания новых полезных фич (дополнительных библиотек, фреймворков, инструментов и т.п.).
Самые большие изменения в реализации из примечаний к выпуску:
- Компилятор и среда выполнения теперь полностью написаны на Go (с небольшим количеством Ассемблера).
- Сборщик мусора теперь является параллельным и обеспечивает значительно меньшее время простоя.
- По умолчанию программы Go запускаются с GOMAXPROCS установленным количеством доступных ядер; в предыдущих выпусках по умолчанию он был равен 1.
- Поддержка внутренних пакетов теперь предоставляется для всех репозиториев, а не только для ядра Go.
- Команда go теперь обеспечивает экспериментальную поддержку внешних зависимостей «vendoring».
- Новая go tool trace команда поддерживает детальную трассировку выполнения программы.
- Новая go doc команда настроена для использования в командной строке.
Талисман
Талисман у Go – Суслик. Интересно, что первоначальная версия талисмана была создана задолго до рождения языка. Его создала Рене Френч для рекламы радиостанции WFMU в Нью-Джерси. Рене Френч было поручено создать футболку для ежегодного сбора средств.
Далее суслик появился в Bell Labs в качестве аватара Боба Фландрена в почтовой системе Bell Labs. Другие рисунки Рене стали аватарами для ken, r, rsc и других. Когда начался проект Go, необходимо было разработать логотип и Рене вызвалась его нарисовать. Он был изображен на первой футболке Go и на сайте Google Code.
Для запуска с открытым исходным кодом в 2009 году Рене предложил адаптировать суслика WFMU в качестве талисмана. И родился суслик-гофер.
В итоге он претерпевал еще несколько изменений в связи с подготовкой мерча и различными событиями и окончательно стал символом языка.
Особенности языка Go
Golang был разработан с учетом особенностей разных языков программирования, включая C, C++, Java, Python и другие. В результате Golang заимствовал и улучшил некоторые черты от своих предшественников, рассмотрим некоторые из них:
Из C и C++
- Синтаксис Go схож с языками из семейства C (такими как C и C++). Включает в себя использование фигурных скобок для блоков кода, точку с запятой в качестве разделителя, операторы присваивания и т.д.
- Golang является компилируемым языком программирования, что позволяет ему достигать высокой производительности. Исходный код на Golang компилируется в машинный код, что делает его эффективным в выполнении.
- Go поддерживает указатели, что позволяет эффективно работать с памятью и применять указатели для передачи данных по ссылке.
- Строки в Golang заключаются в двойные кавычки, что делает их удобными для работы с текстовыми данными.
- Горутины в Golang – это легковесные потоки, а многопоточность в Golang реализуется через механизм горутин. Этот подход аналогичен модели потоков C и C++, но более прост и эффективен.
- В Golang используется возвращаемое значение ошибки для обработки ошибок в функциях.
- Golang занимает промежуточное положение между скоростью выполнения C/C++ и удобством Python/Java.
Из Python
- Golang также как и Python, стремится к простоте и читаемости синтаксиса. Это делает код на Golang более понятным и читаемым, что упрощает разработку и поддержку программ.
- Как Python и Java, Golang также обладает сборщиком мусора (garbage collector), что позволяет автоматически управлять выделением и очисткой памяти, освобождая разработчика от необходимости делать это вручную.
- Golang предоставляет набор встроенных функций и библиотек, аналогичных некоторым из тех, которые доступны в Python. Например, работу с файлами, строками, временем, математическими операциями и т.д.
- Как и в Python, Golang предоставляет свой встроенный тестовый фреймворк для написания модульных тестов и обеспечения стабильности кода.
Из Java
- Сборщик мусора есть как в Python, так и в Java, поэтому Go заимствовал эту функцию из обоих языков.
- Golang также поддерживает интерфейсы, которые позволяют абстрагироваться от конкретной реализации и создавать более гибкий и расширяемый код.
- Как и в Java, Golang предоставляет механизм обработки ошибок с использованием исключений. Однако, в отличие от Java, Golang больше рекомендует использовать возвращаемые значения ошибок для их обработки, чем исключения.
- Подобно Java, Golang использует пакетную структуру, что делает организацию и управление проектами более удобным и позволяет избежать конфликтов имен.
- Golang является языком со строгой статической типизацией. Это означает, что типы данных должны быть объявлены заранее, что обеспечивает более надежный код и облегчает его отладку.
Несмотря на то, что Golang заимствовал некоторые концепции из Python, он также представляет свои уникальные особенности. Помимо простоты, эффективности и масштабируемости, Go обладает несколькими фичами, которые делают его популярным среди разработчиков:
Простотой синтаксис
Официальная документация Go занимает около 50 страниц, просто читается и содержит примеры. Базовый синтаксис в основном относится к семейству C, с некоторым вдохновением от Pascal, Modula и Oberon для деклараций и пакетов. Подход со статически связанными двоичными файлами еще больше снижает сложность времени выполнения.
Пример:
package main
import "fmt"
func main() {
// Строки могут быть сложены с помощью символа `+`.
fmt.Println("go" + "lang")
// Целый числа и числа с плавающей точкой.
fmt.Println("1+1 =", 1+1)
fmt.Println("7.0/3.0 =", 7.0/3.0)
// Логические значения с логическими операторами
fmt.Println(true && false)
fmt.Println(true || false)
fmt.Println(!true)
}
Многопоточность
Встроенные конструкции параллелизма упрощают программистам написание многопоточных приложений. Go использует другой подход, называемый горутинами, которые представляют собой параллельные операции, которые могут выполняться независимо от функции, в которой запущены. Связь и синхронизация между горутинами обрабатываются через типизированный потокобезопасный механизм, называемый каналами. Встроенная поддержка универсальных карт, массивов и срезов также упрощает кодирование.
Наличие «сборщика мусора»
Go использует алгоритм сборки мусора для автоматического определения неиспользуемых объектов и освобождения занимаемой ими памяти. Основным алгоритмом сборки мусора в Go является трёхцветная сборка мусора (tricolor garbage collection), который основан на алгоритме «пометки и освобождения» (mark and sweep). Процесс сборки мусора в Go происходит в фоновом режиме, что позволяет продолжать работу программы без прерываний.
Компилируемость
Исходный код программы на Go должен быть предварительно скомпилирован в машинный код перед его выполнением. Компиляция происходит до того, как программа будет запущена, и она преобразует исходный код на Go в бинарный исполняемый файл, который можно запустить на целевой платформе (операционной системе и архитектуре). Процесс компиляции в Go обычно прост и происходит с использованием встроенного компилятора Go (go), который доступен в стандартной установке Go. Существуют также независимые компиляторы, созданные сторонними разработчиками.
Инструменты разработчика
В Go есть инструменты, которые ускоряют разработку и помогают решать разные задачи:
- go toolchain – комплект инструментов Go включает в себя компилятор, средства форматирования (gofmt) и статического анализа (go vet), а также утилиту для работы с зависимостями (go mod).
- gofmt – инструмент для автоматического форматирования исходного кода в соответствии с официальным стилем Go.
- godoc – найдет комментарии и подготовит из них мануал к программе.
- go vet – утилита для статического анализа и поиска потенциальных ошибок в коде.
- go get – команда для загрузки и установки пакетов из репозитория.
- go mod – инструмент для управления зависимостями в проекте с использованием модулей Go.
- go test – команда для запуска тестов в проекте.
- Delve – отладчик для Go, который позволяет отлаживать код с использованием командной строки или интегрированной среды разработки (IDE).
- Gin или Echo – популярные веб-фреймворки для создания веб-приложений на Go.
- Cobra – библиотека для создания удобных командной строки интерфейсов (CLI) для ваших приложений.
- gRPC и Protobuf – библиотеки для реализации механизма удаленного вызова процедур (RPC) с использованием Protocol Buffers.
- Swagger и go-swagger – инструменты для создания и документирования API с помощью спецификации OpenAPI (Swagger).
- sqlx – библиотека для упрощения работы с базами данных SQL.
- testify – библиотека для упрощения написания и запуска тестов.
- goimports – инструмент для автоматического добавления или удаления импортов в Go-файлах.
- gas – найдет уязвимости.
- typecheck – проверяет соответствие типов в коде.
Для чего используется Golang
Сетевые и веб-серверы, микросервисы, распределенные системы, облачные сервисы и DevOps, веб-разработка, командные интерфейсы (CLI), базы данных и хранилища, проекты с открытым исходным кодом.
Облачная разработка
Go удобен для создания облачных приложений благодаря параллельным и сетевым возможностям, а также высокой степени переносимости. Крупные проекты с открытым исходным кодом, такие как Kubernetes, Docker и Terraform, работают на Go.
Сетевые службы
Параллелизм — это важное свойство для сетевых приложений, и язык Go предоставляет собственные инструменты для реализации параллельных операций, такие как горутины и каналы, которые идеально подходят для таких задач. Поэтому многие проекты на Go становятся полезными для разработки сетевых приложений, распределенных задач и облачных сервисов, таких как API, веб-серверы и простые фреймворки для веб-приложений.
Автономные инструменты и утилиты
Поскольку программы на Go быстро запускаются и могут быть легко упакованы для дальнейшего распространения, они полезны для разработки утилит и других инструментов. Экземпляром является сервер доступа Teleport (в том числе для SSH). Teleport можно быстро и просто установить на серверы, загрузив готовый двоичный файл или создав его из исходного кода.
Материалы по Golang
- Документация по языку Golang
- Эволюция Go от Роберта Гризмера
- Советы по написанию понятного идиоматического кода Go
- 50 оттенков Go: ловушки, подводные камни и распространённые ошибки новичков
Видео
- Why Golang is sucessful by creator of golang by Rob Pike
- Погружение в Google Go – Youtube-серия лекций
- Программирование на Go – Youtube-серия лекций
- Learn Go Programming — Golang Tutorial for Beginners
- dotGo 2016 — Dave Cheney — Do not fear first class functions
- Google I/O 2012 — Go Concurrency Patterns
Курсы
- Курс по изучению Golang для начинающих
- Специализация Programming with Google Go на Coursera
- Functions, Methods, and Interfaces in Go на Coursera
Чуть-чуть рекламы: На виртуальных машинах Serverspace можно развернуть среду разработки для программирования на Go. Вы можете подобрать конфигурацию, необходимую для установки, с помощью калькулятора на сайте или в панели. Также управлять облачной инфраструктурой можно с помощью файлов конфигураций Terraform-провайдера.
Комментарии (18)
sv_kozlov
01.08.2023 12:33+1с некоторым вдохновением от Pascal, Modula и Oberon для деклараций и пакетов.
Вся идея структур с привязкой методов с помощью приемников/ресиверов (receiver) в их объявлениях кажется цельнотянутой с Оберона(2). Ну один в один.
Не только оператор присваивания ":="
anonymous
01.08.2023 12:33НЛО прилетело и опубликовало эту надпись здесь
GospodinKolhoznik
01.08.2023 12:33+5Если уже созданный язык доводить до ума и исправлять ляпы, то это будет уже новый язык (с новыми ляпами). Да и сообщество как правило очень болезненно воспринимает любые изменения, т.к. к старым косякам и ляпам привыкают и их начинают считать за преимущества.
К Go это тоже относится. Язык вроде новый, но упорно косит под древность какую то. Хотя имеет задел стать современным и удобным, но динозавры, которые его создавали нелепые костыли из старых языков перенесли в него, просто потому что они за годы своей жизни так привыкли к тем костылям, что без них уже не могут. Дженерики недавно добавили, но тоже как то криво и убого. Ну как то не тянет то, что называется дженериками в Go на полноценные современные дженерики. Интерфейсы в Go тоже какие то карикатурные.
Но то, что создатели Go послали лесом ООП, за это им огромный плюс в карму.
lazy_val
01.08.2023 12:33+1Что именно в Go вы считаете "нелепыми костылями из старых языков"?
Про ООП согласен. Про дженерики тоже.
GospodinKolhoznik
01.08.2023 12:33Ну например брать аргумент функции в скобочки это просто дань неудобной традиции. Практического смысла в этом нет. Но это так, мелочь. А что серьезная проблема, это то, что функции имеют побочные эффекты. Так не принято делать в математике, но так было принято в старых ЯП и это перетащили и в Go. Иногда это удобно, но сильно мешает рефакторингу. Если бы можно было объявлять часть функций чистыми и часть с побочками, это вывело бы язык совсем на новый уровень.
Error1024
01.08.2023 12:33Ясно, понятно - опять все взято из «си», ок.
А мб стоило посмотреть доклад от одного из создателей Go, чтобы понять что почти все было взято из Modula/Pascal/Oberon, ну, а из «си» элементы синтаксиса, чтобы меньше «воняли».
MigAru
01.08.2023 12:33Я думаю(и знаю что всем по барабану), что сравнивать интерфейсы с java не очень корректно тк по большей части все с С взяли, вроде структур и как раз интерфейсы
includedlibrary
01.08.2023 12:33Только в си нет интерфейсов
MigAru
01.08.2023 12:33Разве?
а это чем не интерфейс
typedef struct base {
int (*foo)(base* me);
} base;
nirom
А как дела с фреймворками? Есть ли полноценные каркасы приложений уровня Spring, Django?
Xeldos
Здесь так не принято.
akurilov
Не надо, пожалуста
Falldot
Все замечательно! Gin, Fiber, Echо. Для работы с БД GORM, Ent и многое другое.
gnomeby
Не знаю как сейчас дела обстоят, но 3 года назад GORM было решением вида компромисс на компромисе, и, хотя оно работало, всё-таки переехали на sqlx.
gnomeby
На Go не очень правильно писать приложения требующие тяжёлые каркасы. Скажем так, если вам надо написать не микросервис/тулу на Go, то вы должны это очень грамотно архитектурно обосновать прежде чем начинать писать.
Даже бекенд сайта в котором будет чуть больше чем просто API уже начинает вызывать боль, если вы писали подобное до этого на "динамических языках".
Xeldos
Но почему тогда мыши продолжают жевать кактус?
gnomeby
Ну в основном стараются не писать на языке то, что на нём туго выходит. Поэтому кактус никто и не жуёт. Наоборот, наслаждение компактностью и продуманностью языка есть.