Совсем другая книга про Go #
“Маленькие книги” Карла Сегуина – лучшее, что только есть в жанре “быстрого старта”. Только самое главное. Без подробностей, в которых так легко утонуть поначалу, но которые потом х так же легко восполнить правильно заданными вопросами и самостоятельно найденными ответами.
Когда-то “Маленькая книга про Go” вдохновила меня написать несколько других “маленьких книг” на темы, для которых книг Карла не было. А потом, когда я сам пришел к Go и вернулся к этой книге, вдруг оказалось, что многое изменилось. Это будет совсем другая книга про Go. Не судите строго.
Go это “C++ для маленьких”. Звучит странно, но именно такие ожидания были в Google от нового языка программирования. Простой, производительный, безопасный. В итоге получился компактный компилируемый язык со строгой типизацией, автоматическим управлением памятью, встроенной поддержкой многозадачности, модульной организацией кода и собственным менеджером пакетов, дающем доступ к большой библиотеке готовых решений, позволяющих даже новичку быть достаточно эффективным.
Он хорош во всем, кроме кривой обучения. В качестве первого языка он не то, чтобы ужасен, но… здесь с самого начала надо знать то, что обычно изучается в последнюю очередь. Рассказывать о нем – настоящий вызов. Но я попробую. Опять же, не судите строго.
Первая программа #
У пресловутого “Hello, World” несколько целей. Во-первых, убедиться, что всё нужное установлено и настроено. Во-вторых, как на первом свидании, увидеть в действии и оценить перспективы. А в-третьих, преодолеть психологический барьер: программа уже написана и работает – осталось только понять, как именно.
В любом текстовом редакторе создайте файл hello.go
:
package main
func main() {
println("Hello, world!")
}
Выполните его:
$ go run hello.go
Hello, world!
Или скомпилируйте и выполните:
$ go build hello.go
$ ./hello
Hello, world!
Однако, простота первой программы обманчива – следующая ступенька больше похожа на высокий забор, для которого нам потребуется отдельная “лесенка”.
Немного теории #
Любое сложное действие можно разделить на простые, те – на еще более простые и так далее, до базовых машинных команд. Это – декомпозиция, основа всего программирования.
Единицей декомпозиции в Go являются функции. Но не те, что в математике (или, скажем, в языке программирования Haskell). Они получают аргументы и возвращают значение, но если “там” значение зависит только от аргументов и, однажды вычисленное, готовое значение всегда просто повторно используется, то “здесь” это скорее подпрограммы, которые каждый раз выполняются.
Где-то между решением шахматного этюда и машинным кодом проходит граница, разделяющая интеллектуальный труд программиста и механическую работу компилятора. Эта граница называется уровнем абстракции и у каждого языка он свой. Все, что ниже этого уровня, компилятор превратит в машинный код сам.
Несколько функций можно собрать в пакет. Пакет это единица компиляции. Каждый пакет компилируется отдельно, а потом из них, как и кубиков, собирается программа. Единица компиляции – сущность атомарная, в конечную программу попадают не только затронутые функции, а весь пакет целиком. Вся стандартная библиотека состоит из пакетов. Чтобы вызвать функцию пакета, его нужно явным образом импортировать. Так компилятор будет знать, какие пакеты собирать в программу.
Функции пакетов стандартной библиотеки вызывают друг друга и это не составляет проблемы – при обновлении все изменения стандартной библиотеки остаются согласованными. Другое дело сторонние библиотеки, которые могут меняться произвольно. Для этого существуют версии. Каждое изменение в пакете приводит к появлению новой версии пакета – то есть код, использующий определенную версию пакета, не сломается.
Модуль – единица организации кода. В модуль входит один или несколько пакетов. У модуля есть версия и это спасает в ситуациях, когда работающая программа перестает собираться из-за того, что какой-то из пакетов за это время обновится и потерял совместимость. Все сторонние библиотеки поставляются именно в виде модулей – с версиями, набором пакетов и зависимостей.
Программы на Go это тоже модули. От библиотечного модуля программа отличается наличием пакета main
с функцией main
– именно с нее начинается выполнение собранной программы.
Вторая “первая” программа #
Теперь построим “настоящую” первую программу.
$ mkdir hello
$ cd hello
$ go mod init hello
Появится файл go.mod
, который выглядит примерно так:
module hello
go 1.24.6
А теперь – файлы с исходным кодом.
demo1.go
package main
func main() {
hello()
}
demo2.go
:
package main
import "fmt"
func hello() {
fmt.Println ("Hello, world!")
}
Тут сразу несколько интересных моментов:
hello.go
(один пакет можно разбить на несколько файлов, главное – указать общее имя в первой строке)
package main
import "fmt"
func hello_en () {
fmt.Println ("Welcome!")
}
func hello_de () {
fmt.Println ("Willkommen!")
}
Создадим вложенный пакет UA
$ mkdir UA
$ cd UA
hitchhiker.go
package hitchhiker
import "fmt"
func Answer() {
fmt.Println("Ultimate answer is", 42)
}
Компилируем и запускаем:
$ go build
$ ./demo
Welcome!
Willkommen!
Ultimate answer is 42
Поздравляю! Пройден самый крутой участок кривой обучения. По сравнению с ним, все остальное будет просто прогулкой.