Перейти до змісту

Типи файлів у дереві Go-коду

Вихідні файли, які розпізнає інструмент go

Шаблон імені файлу Значення
foo.go Звичайний вихідний файл. Компілюється у пакет.
foo_test.go Тестовий файл. Компілюється лише командою go test, ніколи у звичайних збираннях.
foo_linux.go Неявне build-обмеження: компілюється лише коли GOOS=linux.
foo_amd64.go Компілюється лише коли GOARCH=amd64.
foo_linux_amd64.go Компілюється лише коли обидві умови виконуються.
foo_test_linux.go Тестовий файл, обмежений linux.
_foo.go, .foo.go Повністю ігноруються інструментом go. Початковий _ або . — це вимикач.
doc.go Лише конвенція: файл, що містить коментар документації рівня пакету.
go.mod Маніфест модуля.
go.sum База даних контрольних сум модуля / lockfile.
go.work, go.work.sum Файл робочого простору для розробки з кількома модулями.

Анатомія вихідного файлу .go

Кожен Go-вихідний файл дотримується одного скелету:

// Package greet provides a friendly greeting.
package greet                    // 1. оголошення пакету — обов'язкове, перший рядок без коментарів

import (                         // 2. імпорти
    "fmt"
    "strings"
)

const Exclamation = "!"          // 3. оголошення верхнього рівня
                                 //    (const, var, type, func — у будь-якому порядку)

// Hello returns a greeting for name.
func Hello(name string) string {
    name = strings.TrimSpace(name)
    return fmt.Sprintf("Hello, %s%s", name, Exclamation)
}

Два неочевидних правила:

  • Регістр контролює видимість. Ідентифікатори, що починаються з великої літери, експортуються з пакету; з малої — є приватними для пакету. Ключових слів public/private немає — компілятор перевіряє це виключно за іменем.
  • Невикористані імпорти та невикористані локальні змінні є помилками компіляції, а не попередженнями. Це суворо виконується.

Build-обмеження

Build-обмеження вирішують, чи включається файл у збирання.

Явні обмеження (//go:build)

//go:build linux && (amd64 || arm64)

package cache

// ... код лише для linux на 64-бітних процесорах ...

Правила:

  • Рядок //go:build повинен з'являтися перед оголошенням package, якому передують лише порожні рядки та інші коментарі.
  • За ним повинен іти порожній рядок, щоб відрізнити його від коментаря документації пакету.
  • Щонайбільше один рядок //go:build на файл.
  • Вираз використовує булеві оператори: ||, &&, ! та дужки.

Неявні обмеження з імен файлів

Ці обмеження виникають із суфіксів імен файлів — коментар не потрібен.

  • server_linux.go → ефективне обмеження //go:build linux
  • math_amd64.go//go:build amd64
  • utils_windows_386.go//go:build windows && 386

Автоматично задоволені теги

Під час будь-якого збирання ці теги є істинними:

  • Поточне значення GOOS (наприклад, linux, darwin, windows).
  • Поточне значення GOARCH (наприклад, amd64, arm64).
  • Тег unix на будь-якій Unix-подібній ОС.
  • Використовуваний компілятор: gc або gccgo.
  • cgo, якщо cgo увімкнено.
  • Тег для кожної версії Go аж до поточної: go1.1, go1.21, go1.22, ...
  • Будь-які власні теги, передані через -tags команді go.

Тестові файли — два різновиди

Тестовий файл може оголошувати той самий пакет, який тестує, або окремий пакет _test.

// foo_test.go — внутрішній тест (може бачити неекспортовані ідентифікатори)
package foo

import "testing"

func TestAdd(t *testing.T) {
    if got := add(2, 3); got != 5 {
        t.Errorf("add(2,3) = %d; want 5", got)
    }
}
// foo_test.go — зовнішній тест (тестує лише публічний API)
package foo_test

import (
    "testing"
    "example.com/foo"
)

func TestPublic(t *testing.T) { /* ... */ }

Пакет може мати обидва різновиди. Тестові файли також можуть визначати:

  • BenchmarkXxx(b *testing.B) — бенчмарки продуктивності.
  • FuzzXxx(f *testing.F) — fuzz-тести.
  • ExampleXxx() — запустимі приклади, що одночасно служать документацією.

go.mod — як виглядає кожна директива

go.mod — це рядково-орієнтований текстовий файл у кодуванні UTF-8. Повний приклад із кожною директивою:

module example.com/myapp

go 1.23.0

toolchain go1.23.4

require (
    github.com/gorilla/mux v1.8.1
    golang.org/x/crypto v0.21.0 // indirect
)

exclude github.com/some/pkg v1.4.0

replace github.com/some/pkg => ../local/pkg

retract v1.0.1                            // do not depend on this version of MY module

godebug panicnil=1
Директива Призначення
module Канонічний шлях імпорту модуля. Використовується рівно один раз.
go Мінімальна версія мови Go, якої потребує цей модуль.
toolchain Рекомендована версія toolchain для розробки та CI.
require Залежність у конкретній мінімальній версії. // indirect позначає транзитивні залежності.
exclude Відхилити конкретну версію залежності.
replace Перенаправити модуль на локальний шлях або форк.
retract Позначити версії власного модуля як ті, що не слід використовувати.
godebug Зафіксувати перемикач GODEBUG, коли цей модуль є головним.
tool Оголосити інструмент Go, запустити який можна через go tool.

Не редагуйте go.mod вручну для рутинних змін. Використовуйте go get, go mod tidy тощо — вони знають про go.sum і збережуть обидва файли узгодженими.

go.sum — як він виглядає

Два рядки на кожну пару (module, version):

golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
  • Перший рядок: хеш повного zip-архіву модуля.
  • Другий рядок: хеш лише файлу go.mod цього модуля.

Другий рядок дозволяє Go перевіряти транзитивні метадані без завантаження відповідних модулів. Обидва рядки записуються та перевіряються командою go автоматично. Ніколи не редагуйте go.sum вручну.

Джерела