Moduł to drzewo katalogów z pakietami Go i plikiem go.mod w korzeniu. go.mod nadaje modułowi nazwę i wymienia wersje wszystkich innych modułów, od których zależy. Moduł tworzysz przez go mod init:
mkdir myapp
cd myapp
go mod init example.com/myapp
go: creating new go.mod: module example.com/myapp
Powstały go.mod:
module example.com/myapp
go 1.24.5
To wystarczy do budowania. Każdy projekt Go od Go 1.16 jest modułem, a go build, go run . i go test bez modułu odmawiają działania:
go: go.mod file not found in current directory or any parent directory; see 'go help modules'
Wybór ścieżki modułu
Ścieżka modułu to prefiks każdej ścieżki importu wewnątrz modułu. W module example.com/myapp pakiet z katalogu internal/store importuje się jako example.com/myapp/internal/store.
| Sytuacja | Ścieżka modułu |
|---|---|
| Kod na GitHubie, który inni mogą importować | github.com/yourname/project |
| Kod twojej firmy | yourcompany.com/project lub URL repozytorium |
| Prywatny program lub ćwiczenie | example.com/myapp albo po prostu myapp |
| Wersja 2 lub nowsza opublikowanego modułu | github.com/yourname/project/v2 |
W przypadku biblioteki ścieżka musi odpowiadać miejscu, w którym leży kod, bo go get używa jej do znalezienia repozytorium. W przypadku programu, który uruchamiasz tylko ty, ścieżka to po prostu nazwa. Unikaj pojedynczego słowa, które pokrywa się z pakietem biblioteki standardowej, jak go mod init fmt czy go mod init strings: build kończy się wtedy błędem ambiguous import: found package fmt in multiple modules.
Uruchomienie go mod init bez argumentu poza starym układem GOPATH kończy się błędem:
go: cannot determine module path for source directory /home/ana/myapp (outside GOPATH, module path must be specified)
Podaj ścieżkę.
Dodawanie zależności
Napisz import, a potem pozwól Go go pobrać. Załóżmy, że main.go importuje github.com/google/uuid. Budowanie, zanim moduł o nim wie, daje jasną instrukcję:
main.go:6:2: no required module provides package github.com/google/uuid; to add it:
go get github.com/google/uuid
Naprawi to każda z tych komend:
go get github.com/google/uuid
# or, to sync go.mod with every import in the module:
go mod tidy
go get zgłasza, co zmieniło:
go: downloading github.com/google/uuid v1.6.0
go: added github.com/google/uuid v1.6.0
go mod tidy zgłasza, jak rozwiązało import:
go: finding module for package github.com/google/uuid
go: downloading github.com/google/uuid v1.6.0
go: found github.com/google/uuid in github.com/google/uuid v1.6.0
go.mod ma teraz linię require:
module example.com/myapp
go 1.24.5
require github.com/google/uuid v1.6.0
go get z wersjami
| Komenda | Efekt |
|---|---|
go get pkg | dodaje pkg w najnowszym wydaniu albo zostawia obecną wersję, jeśli już jest wymagany |
go get pkg@v1.5.0 | używa dokładnie v1.5.0 (podniesienie lub obniżenie wersji) |
go get pkg@latest | przechodzi na najnowsze wydanie |
go get pkg@abc1234 | używa konkretnego commita (zapisanego jako pseudowersja) |
go get -u ./... | podnosi każdą zależność do najnowszego wydania minor lub patch |
go get -u=patch ./... | podnosi tylko do najnowszych wydań patch |
go get pkg@none | usuwa wymaganie |
go get go@1.24 | podnosi minimalną wersję Go modułu |
go get zmienia go.mod. Nie buduje już ani nie instaluje programów; od Go 1.18 to zadanie go install pkg@version.
Zależności pośrednie
Wymagania oznaczone // indirect to moduły, których twój kod nie importuje bezpośrednio, ale których potrzebuje build. Od Go 1.17 go.mod wymienia każdy moduł dostarczający pakiet do buildu, więc zależności twoich zależności pojawiają się tu z tym oznaczeniem. Tymi oznaczeniami zarządza go mod tidy; nie dodajesz ich ręcznie.
go mod tidy
Uruchamiaj go mod tidy za każdym razem, gdy dodajesz lub usuwasz importy. Ta komenda:
- dodaje brakujące wymagania dla importowanych pakietów,
- usuwa wymagania, których nic już nie importuje,
- dodaje wpisy
go.sumpotrzebne do buildu i usuwa nieaktualne.
Przegląda każdy pakiet w module, łącznie z testami i każdą kombinacją tagów budowania, więc czasem zostawia zależność, której na twojej platformie nie widać w użyciu. Uruchamianie go mod tidy przed każdym commitem i sprawdzanie w CI, że nie daje żadnego diffa, utrzymuje go.mod w porządku.
go.sum
go.sum zapisuje hash każdej wersji modułu, której używa build:
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
Pierwsza linia to hash plików modułu, druga tylko jego go.mod. Gdy komenda go pobiera moduł, sprawdza hash z go.sum i z publiczną bazą sum kontrolnych (sum.golang.org), więc zmanipulowane lub po cichu zmienione wydanie przerywa build. Commituj go.sum razem z go.mod i nigdy nie edytuj go ręcznie.
Jak Go wybiera wersje
Go używa minimalnego wyboru wersji (minimal version selection). Każdy moduł podaje minimalną wersję każdej potrzebnej zależności, a build używa najwyższego z tych minimów, nigdy niczego nowszego. Jeśli twój moduł wymaga uuid v1.5.0, a zależność wymaga uuid v1.6.0, build użyje v1.6.0, nawet jeśli istnieje v1.7.0. Nic się nie aktualizuje, dopóki ktoś o to nie poprosi przez go get.
W efekcie buildy są powtarzalne bez pliku lock: go.mod razem z grafem zależności w pełni wyznacza każdą wersję. go list -m all wypisuje wynik:
go list -m all
example.com/myapp
github.com/google/uuid v1.6.0
Wersje główne
Moduł w wersji v2 lub wyższej musi zawierać numer wersji głównej w ścieżce: github.com/yourname/project/v2. Razem z nią zmienia się ścieżka importu, więc project i project/v2 to różne moduły i oba mogą występować w jednym buildzie. To reguła Go dla zmian łamiących kompatybilność i dlatego widzisz importy takie jak github.com/jackc/pgx/v5.
replace: lokalna praca nad zależnością
Żeby przetestować zmiany w zależności przed ich opublikowaniem, skieruj jej ścieżkę na lokalny katalog:
module example.com/myapp
go 1.24.5
require example.com/mylib v1.2.0
replace example.com/mylib => ../mylib
Albo z wiersza poleceń:
go mod edit -replace example.com/mylib=../mylib
go mod tidy
Katalog musi zawierać własny go.mod. replace działa tylko przy bezpośrednim budowaniu tego modułu, a nie wtedy, gdy ktoś inny od niego zależy, więc pamiętaj, żeby usunąć je przed otagowaniem wydania.
Do edycji kilku modułów naraz bez ruszania ich plików go.mod Go 1.18 dodało przestrzenie robocze (workspaces):
go work init . ../mylib
To zapisuje plik go.work, dzięki któremu lokalny mylib ma pierwszeństwo. Nie dodawaj go.work do systemu kontroli wersji, chyba że cały zespół używa tego samego układu.
Zależności narzędziowe (Go 1.24)
Go 1.24 dodało dyrektywę tool, więc generatory kodu i lintery mogą mieć wersje zapisane w go.mod, zamiast być instalowane globalnie:
go get -tool golang.org/x/tools/cmd/stringer
go tool stringer -type=Color
func init to coś innego
Wyszukiwania "golang init" często dotyczą funkcji init, która nie ma nic wspólnego z go mod init. Każdy pakiet może zadeklarować func init(). Nie przyjmuje argumentów, twój kod nie może jej wywołać i wykonuje się raz, automatycznie, po ustawieniu zmiennych na poziomie pakietu, a przed main:
Plik może mieć kilka funkcji init i wykonują się one w kolejności, w jakiej występują. Importowane pakiety najpierw kończą własną inicjalizację. Utrzymuj init małe: pracę, która może się nie powieść, łatwiej obsłużyć i przetestować jako zwykłą funkcję wywoływaną z main.
Moduły prywatne i proxy
Domyślnie go pobiera moduły przez proxy.golang.org. To proxy nie widzi prywatnych repozytoriów, więc powiedz Go, które ścieżki są prywatne:
go env -w GOPRIVATE=github.com/yourcompany/*
Moduły pasujące do GOPRIVATE są pobierane bezpośrednio z repozytorium z twoimi danymi logowania git i pomijają bazę sum kontrolnych.
Najczęściej zadawane pytania
Co robi go mod init?
Tworzy plik go.mod w bieżącym katalogu, dzięki czemu ten katalog staje się korzeniem modułu. go mod init example.com/myapp zapisuje ścieżkę modułu i wersję Go:
module example.com/myapp
go 1.24.5
Uruchom to raz na projekt, przed go build lub go get.
Jakiej ścieżki modułu użyć w go mod init?
Adresu, spod którego kod będzie pobierany, jeśli inni go zaimportują, zwykle ścieżki repozytorium: go mod init github.com/yourname/project. Dla programu, którego nikt nie będzie importował, zadziała dowolna nazwa (go mod init myapp), ale ścieżka w stylu domeny z kropką, taka jak example.com/myapp, pozwala uniknąć kolizji z nazwami pakietów biblioteki standardowej.
Czym różni się go get od go mod tidy?
go get pkg@version dodaje zależność lub zmienia jej wersję. go mod tidy czyta pliki źródłowe, dodaje każdy moduł potrzebny twoim importom, którego brakuje w go.mod, usuwa wymagania, których nic nie importuje, i aktualizuje go.sum. Typowy przebieg to napisanie importu, a potem uruchomienie go mod tidy.
Czy commitować go.sum?
Tak. go.sum przechowuje kryptograficzne hashe każdej wersji modułu, której używa build. Scommitowanie go pozwala komendzie go sprawdzić, że wszyscy pobierają bajt w bajt identyczne zależności. Nigdy nie edytuj go ręcznie; utrzymuje go go mod tidy.
Czy "golang init" to to samo co go mod init?
Nie, to różne rzeczy, które łączy jedno słowo. go mod init to komenda terminala, która tworzy go.mod. func init() to funkcja, którą piszesz w kodzie Go; wykonuje się automatycznie raz, przed main, po zainicjalizowaniu zmiennych pakietu.