# Basic

## Создание проекта

```
$ mkdir project
$ cd project
$ go mod init project
```

Или

```
$ go mod init github.com/IkeMurami/test-go-project
$ cat go.mod
```

## Структура проекта

### Пакеты и модули

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

**Package** — набор скриптов и файлов, находящихся в одной директории или отнесенных к одному пакету через директиву `package` (в одной директории не может быть двух разных пакетов). Все классы, объекты, типы и тп видны в рамках одного пакета. Go программы организуются в такие пакеты.

**Module** — коллекция пакетов. Репозитории состоят из модулей (обычно только один модуль находящийся в корне (`/`) репозитория). Файл `go.mod` определяет module path — import path prefix для всех пакетов внутри модуля.&#x20;

```
package/
    mod1/
        go.mod
    mod2/
        go.mod
    ...
    
или

package/
    go.mod
```

### Что еще может быть в Go-проекте

```
package/
    vendor/ — сюда будут складываться зависимости
    tests/ — для тестов
    tools/ - для кодогенерации
        tools.go - инструменты, которые запускаются на этапе сборки проекта
        generate.go - кодогенерация (например, protobuf'ы)
    configs/ — для конфигов
    cmd/ — для кода, который запускается через командную строкую. Грубо говоря для бинарников
    pkg/ — для всего кода (в том числе и того, который экспортируемый)
    internal/ — код, который мы не позволяем экспортировать: https://golang.org/cmd/go/#hdr-Internal_Directories
    build/ — для докерфайлов и всего, что нужно для билда
        migrations/ — для миграции с версии на версию баз
        package/ — для сборки пакета
    bin/ — куда бинари будут класться собранные
    service/ — клиенты к другим сервисам (kafka, rabbit, текущий сервис)
    .gitignore — что не должно попадать в репозиторий (конфиги например)
    .dockerignore — что не должно попасть в докер контейнер (конфиги например)
    README.md — описание
    Makefile
    ...
    другие ci штуки
```

## Работа с зависимостями

### go.mod

Инициализируем `go.mod` файл. Указывает, что это модуль и ваш код может быть переиспользован. Так же этот файл хранит зависимости.

```
go mod init <project-name>

Например:
go mod init test_project
go mod init mysite.com/project-name
go mod init github.com/tests/ttests
```

### Локальные зависимости

Допустим, что вы (`main_project`) имеете зависимость от локального проекта (`test_project`), тогда в go.mod добавляем строчку:

```
module main_project

go 1.14

replace mysite.com/test_project => ../test_project
```

Теперь в коде можно использовать еще неопубликованный проект.

Или то же, с помощью `go mod`:

```
$ go mod edit -replace github.com/pselle/bar=/Users/pselle/Projects/bar
```

### Добавление внешних зависимостей

После создания `go.mod` (`-u` означает добавление не в `GOPATH`, а локально):

```
$ go get -u golang.org/x/lint/golint
```

### Очистка от неиспользуемых пакетов

Перед созданием релиза рекомендуется очистить проект от лишних зависимостей, которые не используются

```
$ go mod tidy
$ cat go.mod
```

## Компиляция

### Введение

_gc_ - стандартный компилятор языка Go. В его состав входят:&#x20;

* программы компиляции _5g_, _6g_ и _8g_
* программы компоновки _51_, _61_ и _81_
* _godoc —_ для просмотра документации

5 — ARM\
6 — AMD64\
8 — Intel 386

К счастью, есть одна высокоуровневая обертка — _go._

В комплект Go входит инструмент `cgo`, обеспечивающий возможность использования внешнего программного кода на C в программах на языке Go. В Linux и BSD-системах имеется возможность использовать код на C и C++ с помощью инструмента SWIG ([www.swig.org](https://www.swig.org)). Помимо `gc`, имеется также компилятор `gccgo` (интерфейс к компилятора `gcc` — GNU Compiler Collection — для языка Go).

### Правка, компиляция и запуск

```
Собрать пакет и положить бинарь рядом:
$ go build [-o /path/to/binary]

про кросс-компиляцию: https://habr.com/ru/post/249449/

пример: win:
GOOS=windows GOARCH=386 go build -o http_example.exe
GOOS=windows GOARCH=amd64 go build -o http_example64.exe

Собрать пакет и положить бинарь в %GOROOT%\bin:
$ go install
```

### go cmd

Документация по go cli: [https://pkg.go.dev/cmd/go](https://pkg.go.dev/cmd/go)

## Дополнительные инструменты

### tools.go

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

Пример

```go
// +build tools

package main

import (
	_ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2"
)
```

`// +build tools` — **build constraint** a.k.a. **build tag**

### Кодогенерация

Есть такая инструкция `go generate`. Она позволяет создать или исполнить код до запуска программы (`go build`). Например, запустить bash-скрипт, создать код для proto-структур и классов, доставить dev-зависимости...

Как встроить это в проект — создать рядом с `main.go`, файл `generate.go`:

```go
package main

//go:generate scripts/protobuf.sh
//go:generate go install github.com/some/package
//go:generate protoc -I=. --go_out=. --go_opt=paths=source_relative ./protocol/some.proto
```

На этапе сборки проекта (до `go build`) скрипт `generate.go` будет выполнен.

## Форматирование кода

```
gofmt -w test.go
go fmt /path/to/project
```
