Установка Go Ссылка на заголовок

Устанавливается Go как и любое другое приложение. Для Windows установщик можно скачать с golang.org/dl/. Под Linux можно установить через пакетный менеджер. Для macOS тоже есть установщик, однако если установить через Homebrew, то будет проще обновлять.

Результат установки можно проверить в терминале (в случае Windows - в PowerShell) используя команду go version.

PowerShell (Windows 10)

PowerShell (Windows 10)

Мир Go до 1.11 Ссылка на заголовок

До версии 1.11, любой Go код должен был находиться внутри директории называемой рабочим пространством. Эта директория задается переменной окружения GOPATH. Узнать текущее расположение можно используя команду go env.

Внутри этой директории находятся три поддиректории:

  • bin — для скомпилированных исполняемых файлов,
  • pkg — для установленных пакетов,
  • src — для исходного кода пакетов.

Каждый пакет внутри src представлен в виде директории с Go файлами. Путь к директории после $GOPATH/src/ называется import path. Типично import path содержит в себе информацию о том, откуда этот пакет можно скачать. Например github.com/golang/glog или gopkg.in/yaml.v2.

$GOPATH
|-- bin
|   `-- ...
|-- pkg
|   `-- ...
`-- src
    |-- github.com
    |   |-- golang
    |   |   `-- glog
    |   |       |-- glog.go
    |   |       `-- ...
    |   `-- ...
    `-- golang.org
        `-- x
            |-- crypto
            |   `-- ...
            `-- ...

Данную иерархию поддерживает go get — команда, которая скачивает и устанавливает пакеты. Установим, например, goimports:

go get golang.org/x/tools/cmd/goimports

После выполнения этой команды в src будет исходный код goimports и всех зависимостей, а в bin будет собранный исполняемый бинарный файл.

Отсутствие версий в GOPATH Ссылка на заголовок

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

Однако знакомые со сломанными зависимостями могут удивиться: человеческий фактор никто не отменял, иногда обновление зависимостей все-таки ломает существующий код. Как быть?

Если автор пакета не хотел ломать зависимые пакеты, то поломка обратной совместимости — это ошибка и она должна быть исправлена как можно быстрее.

В ситуациях, когда нет возможности сохранить обратную совместимость или нет желания, у пакета принято менять import path. Например, был k8s.io/klog, стал k8s.io/klog/v2.

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

Модули Ссылка на заголовок

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

Модуль — это набор пакетов. На файловой системе модуль представлен как директория с исходниками пакетов и файлом go.mod. И модуль может находиться вне GOPATH.

tools
|-- go.mod
|-- cmd
|   |-- goimports
|   |   |-- goimports.go
|   |   `-- ...
|   `-- ...
`-- ...

Внутри go.mod задается module path — начальная часть import path для пакетов внутри этого модуля, например golang.org/x/tools.

Если модуль вне GOPATH, то как Go найдет его при сборке других пакетов? Никак, при сборке других модулей Go не будет искать этот модуль на файловой системе, он просто будет скачен из интернета.

Hello, world! Ссылка на заголовок

Итак, пришло время для первой программы. Это будет простой HTTP-сервер, который на любой запрос отдавать страницу с Hello, world!

Создадим модуль hello-go. Для этого в терминале создадим директорию hello-go (команда mkdir), перейдем внутрь её (cd) и создадим модуль (go mod init).

$ mkdir hello-go
$ cd ./hello-go
hello-go$ go mod init hello-go
go: creating new go.mod: module hello-go

Теперь внутри директории есть файл go.mod.

Создадим в любимом текстовом редакторе, например Visual Studio Code, файл main.go со следующим текстом:

package main

import (
    "fmt"
    "log"
    "net/http"
    "os"

    "github.com/gorilla/handlers"
)

func HelloHandler(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "Hello, world!\n")
}

func main() {
    m := http.NewServeMux()
    m.HandleFunc("/", HelloHandler)

    handler := handlers.CombinedLoggingHandler(os.Stdout, m)

    s := &http.Server{
        Addr:    ":8080",
        Handler: handler,
    }

    fmt.Println("Listening at http://localhost:8080")
    log.Fatal(s.ListenAndServe())
}

Останавливаться на синтаксисе не буду, для этого есть A Tour of Go, однако хочу заметить, что fmt, log, net/http и os входят в стандартную библиотеку Go. А вот github.com/gorilla/handlers — это сторонний пакет.

Запустим эту программу. Для этого в терминале, все еще находясь внутри директории hello-go, нужно выполнить go run.

hello-go$ go run ./main.go
go: downloading github.com/gorilla/handlers v1.5.0
go: downloading github.com/felixge/httpsnoop v1.0.1
Listening at http://localhost:8080

Сначала Go скачивает используемый пакет github.com/gorilla/handlers вместе с его зависимостью, а потом запускает программу. Проверить сервер можно перейдя по ссылке http://localhost:8080. Благодаря CombinedLoggingHandler в терминале появится информация о клиенте, который зашел на страницу.

После успешной сборки программы, в go.mod фиксируются версии использованных зависимостей, в данном случае будет зафиксирована версия github.com/gorilla/handlers. При следующей сборке уже будет использовать именно эту версию, что позволит воспроизвести сборку годами позже.