Skip to content

Modul

Setiap bahasa modern memiliki tool manajemen dependensi yang matang, seperti Gradle untuk Java, Pip untuk Python, Npm untuk NodeJs, dll. Tool manajemen dependensi yang baik dapat menghemat banyak waktu bagi developer dan meningkatkan efisiensi pengembangan. Namun Go di awal tidak memiliki solusi manajemen dependensi yang matang, saat itu semua kode disimpan di direktori GOPATH, sangat tidak ramah untuk proyek engineering, versi kacau, dependensi sulit dikelola. Untuk menyelesaikan masalah ini, developer komunitas besar berdebat, situasi sempat kacau,期间 juga muncul beberapa yang unggul seperti Vendor, sampai Go1.11官方 akhirnya meluncurkan tool manajemen dependensi官方 Go Mod, mengakhiri situasi kacau sebelumnya, dan terus disempurnakan di update berikutnya, mengeliminasi tool lama. Hingga kini, saat menulis artikel ini, versi rilis Go sudah mencapai 1.20, hari ini hampir semua proyek Go mengadopsi Go Mod, oleh karena itu artikel ini hanya akan memperkenalkan Go Mod,官方 juga menulis dokumentasi yang sangat detail untuk modul Go: Go Modules Reference.

Go Module pada dasarnya berbasis VCS (Version Control System), saat Anda mendownload dependensi, sebenarnya mengeksekusi command VCS, seperti git. Jadi jika ingin membagikan library yang Anda tulis, hanya perlu memenuhi tiga hal berikut:

  • Repository source code dapat diakses publik, dan VCS termasuk salah satu berikut:
    • git
    • hg (Mercurial)
    • bzr (Bazaar)
    • svn
    • fossil
  • Adalah proyek go mod yang sesuai spesifikasi
  • Sesuai dengan spesifikasi semantic versioning

Jadi Anda hanya perlu normal mengembangkan menggunakan VCS, dan memberi tag versi spesifik Anda dengan Tag yang sesuai standar, orang lain dapat mendownload library yang Anda tulis melalui nama modul. Berikut akan mendemonstrasikan beberapa langkah pengembangan modul melalui contoh.

Repository contoh: 246859/hello: say hello (github.com)

Persiapan

Sebelum memulai pastikan versi Anda cukup untuk sepenuhnya mendukung go mod (go >= 1.17), dan mengaktifkan Go Module, lihat apakah sudah aktif melalui command berikut

bash
$ go env GO111MODULE

Jika belum aktif, aktifkan Go Module melalui command berikut

bash
$ go env -w GO111MODULE=on

Membuat

Pertama Anda perlu repository source code yang dapat diakses publik, ada banyak pilihan, saya cukup merekomendasikan Github. Buat proyek baru di sana, beri nama hello, nama repository meskipun tidak ada batasan khusus, tetapi disarankan tidak menggunakan karakter spesial, karena ini akan mempengaruhi nama modul.

Setelah selesai membuat, dapat dilihat URL repository adalah https://github.com/246859/hello, nama modul Go yang sesuai adalah github.com/246859/hello.

Lalu clone ke lokal, inisialisasi modul melalui command go mod init.

bash
$ git clone git@github.com:246859/hello.git
Cloning into 'hello'...
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 5 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (5/5), done.

$ cd hello && go mod init github.com/246859/hello
go: creating new go.mod: module github.com/246859/hello

Lalu dapat melakukan pengembangan, fungsinya sangat sederhana, hanya satu fungsi

go
// hello.go
package hello

import "fmt"

// Hello returns hello message
func Hello(name string) string {
        if name == "" {
                name = "world"
        }
        return fmt.Sprintf("hello %s!", name)
}

Sekaligus tulis file tes untuk unit test

go
// hello_test.go
package hello_test

import (
        "testing"
        "fmt"
        "github.com/246859/hello"
)

func TestHello(t *testing.T) {
        data := "jack"
        expected := fmt.Sprintf("hello %s!", data)
        result := hello.Hello(data)

        if result != expected {
                t.Fatalf("expected result %s, but got %s", expected, result)
        }

}

Selanjutnya tulis program command line untuk output hello, fungsinya juga sangat sederhana. Untuk program command line, sesuai norma dibuat di cmd/app_name/ proyek, jadi file program command line hello disimpan di direktori cmd/hello/, lalu tulis kode terkait di dalamnya.

go
// cmd/hello/main.go
package main

import (
  "flag"
  "github.com/246859/hello"
  "os"
)

var name string

func init() {
  flag.StringVar(&name, "name", "world", "name to say hello")
}

func main() {
  flag.Parse()
  msg := hello.Hello(name)
  _, err := os.Stdout.WriteString(msg)
  if err != nil {
    os.Stderr.WriteString(err.Error())
  }
}

Testing

Setelah menulis selesai, format source code dan test

bash
$ go fmt && go vet ./...

$ go test -v .
=== RUN   TestHello
--- PASS: TestHello (0.00s)
PASS
ok      github.com/246859/hello 0.023s

Jalankan program command line

bash
$ go run ./cmd/hello -name jack
hello jack!

Dokumentasi

Terakhir, perlu menulis README yang ringkas dan jelas untuk library ini, agar developer lain sekilas tahu cara menggunakannya

markdown
# hello

just say hello

## Install

import code

```bash
go get github.com/246859/hello@latest
```

install cmd

```bash
go install github.com/246859/hello/cmd/hello@latest
```

## Example

Here's a simple example as follows:

```go
package main

import (
  "fmt"
  "github.com/246859/hello"
)

func main() {
  result := hello.Hello("jack")
  fmt.Println(result)
}
```

Ini adalah dokumen README yang sangat sederhana, Anda juga dapat memperkayanya sendiri.

Upload

Setelah semua kode ditulis dan test selesai, dapat submit dan push modifikasi ke repository remote.

bash
$ git add go.mod hello.go hello_test.go cmd/ example/ README.md

$ git commit -m "chore(mod): mod init" go.mod
[main 5087fa2] chore(mod): mod init
 1 file changed, 3 insertions(+)
 create mode 100644 go.mod

$ git commit -m "feat(hello): complete Hello func" hello.go
[main 099a8bf] feat(hello): complete Hello func
 1 file changed, 11 insertions(+)
 create mode 100644 hello.go

$ git commit -m "test(hello): complete hello testcase" hello_test.go
[main 76e8c1e] test(hello): complete hello testcase
 1 file changed, 17 insertions(+)
 create mode 100644 hello_test.go

$ git commit -m "feat(hello): complete hello cmd" cmd/hello/
[main a62a605] feat(hello): complete hello cmd
 1 file changed, 22 insertions(+)
 create mode 100644 cmd/hello/main.go

$ git commit -m "docs(example): add hello example" example/
[main 5c51ce4] docs(example): add hello example
 1 file changed, 11 insertions(+)
 create mode 100644 example/main.go

$ git commit -m "docs(README): update README" README.md
[main e6fbc62] docs(README): update README
 1 file changed, 27 insertions(+), 1 deletion(-)

Total enam commit tidak banyak, setelah submit buat tag untuk commit terbaru

bash
$ git tag v1.0.0

$ git tag -l
v1.0.0

$ git log --oneline
e6fbc62 (HEAD -> main, tag: v1.0.0, origin/main, origin/HEAD) docs(README): update README
5c51ce4 docs(example): add hello example
a62a605 feat(hello): complete hello cmd
76e8c1e test(hello): complete hello testcase
099a8bf feat(hello): complete Hello func
5087fa2 chore(mod): mod init
1f422d1 Initial commit

Terakhir push ke repository remote

bash
$ git push --tags
Enumerating objects: 23, done.
Counting objects: 100% (23/23), done.
Delta compression using up to 16 threads
Compressing objects: 100% (17/17), done.
Writing objects: 100% (21/21), 2.43 KiB | 1.22 MiB/s, done.
Total 21 (delta 5), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (5/5), done.
To github.com:246859/hello.git
   1f422d1..e6fbc62    main -> main
  * [new tag]         v1.0.0 -> v1.0.0

Setelah push selesai, buat release untuk itu (ada tag sudah cukup, release hanya sesuai norma github)

Dengan demikian, penulisan modul selesai, di atas adalah proses dasar pengembangan modul, developer lain dapat mengimport kode atau menginstal tool command line melalui nama modul.

Mengimport

Referensi library melalui go get

bash
$ go get github.com/246859/hello@latest
go: downloading github.com/246859/hello v1.0.0
go: added github.com/246859/hello v1.0.0

Instal program command line melalui go install

bash
$ go install github.com/246859/hello/cmd/hello@latest && hello -name jack
hello jack!

Atau langsung jalankan menggunakan go run

bash
$ go run -mod=mod github.com/246859/hello/cmd/hello -name jack
hello jack!

Setelah library direferensikan, Go Package akan membuat halaman khusus untuknya, proses ini otomatis, developer tidak perlu melakukan pekerjaan apa pun, misalnya library hello memiliki halaman dokumentasi eksklusif, seperti ditunjukkan di bawah ini.

Untuk informasi lebih detail tentang upload modul,前往 Add a package.

Untuk informasi tentang cara menghapus informasi modul,前往 Removing a package.

Mengatur Proxy

Go meskipun tidak memiliki central repository seperti Maven Repo, PyPi, NPM, tetapi memiliki proxy repository官方: Go modules services (golang.org), ia akan meng-cache modul yang didownload developer sesuai versi dan nama modul. Namun karena servernya deployed di luar negeri, kecepatan akses tidak ramah bagi user domestik, oleh karena itu perlu memodifikasi alamat proxy modul default, saat ini di domestik yang cukup baik ada beberapa berikut:

Di sini memilih proxy Qiniu Cloud, jalankan command berikut untuk memodifikasi proxy Go,其中 direct表示 setelah proxy download gagal bypass cache proxy langsung akses repository source code.

sh
$ go env -w GOPROXY=https://goproxy.cn,direct

Setelah proxy berhasil dimodifikasi, di masa depan mendownload dependensi akan sangat cepat.

Mendownload Dependensi

Setelah memodifikasi proxy, selanjutnya coba instal dependensi third-party,官方 Go memiliki website query dependensi khusus: Go Packages.

Referensi Kode

Cari framework Web terkenal Gin di dalamnya.

Di sini akan muncul banyak hasil pencarian, saat menggunakan dependensi third-party, perlu mempertimbangkan apakah mengadopsi dependensi ini berdasarkan jumlah referensi dan waktu update, di sini langsung pilih yang pertama

Setelah masuk halaman yang sesuai, dapat dilihat ini adalah halaman dokumentasi dependensi ini, ada sangat banyak informasi detail tentangnya, saat membaca dokumentasi berikutnya juga dapat ke sini.

Di sini hanya perlu copy alamatnya, lalu di proyek yang dibuat sebelumnya gunakan command go get, command sebagai berikut

sh
$ go get github.com/gin-gonic/gin

Prosesnya akan mendownload banyak dependensi, selama tidak error berarti download berhasil.

sh
$ go get github.com/gin-gonic/gin
go: added github.com/bytedance/sonic v1.8.0
go: added github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311
go: added github.com/gin-contrib/sse v0.1.0
go: added github.com/gin-gonic/gin v1.9.0
go: added github.com/go-playground/locales v0.14.1
go: added github.com/go-playground/universal-translator v0.18.1
go: added github.com/go-playground/validator/v10 v10.11.2
go: added github.com/goccy/go-json v0.10.0
go: added github.com/json-iterator/go v1.1.12
go: added github.com/klauspost/cpuid/v2 v2.0.9
go: added github.com/leodido/go-urn v1.2.1
go: added github.com/mattn/go-isatty v0.0.17
go: added github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421
go: added github.com/modern-go/reflect2 v1.0.2
go: added github.com/pelletier/go-toml/v2 v2.0.6
go: added github.com/twitchyliquid64/golang-asm v0.15.1
go: added github.com/ugorji/go/codec v1.2.9
go: added golang.org/x/arch v0.0.0-20210923205945-b76863e36670
go: added golang.org/x/crypto v0.5.0
go: added golang.org/x/net v0.7.0
go: added golang.org/x/sys v0.5.0
go: added golang.org/x/text v0.7.0
go: added google.golang.org/protobuf v1.28.1
go: added gopkg.in/yaml.v3 v3.0.1

Setelah selesai lihat file go.mod

sh
$ cat go.mod
module golearn

go 1.20

require github.com/gin-gonic/gin v1.9.0

require (
  github.com/bytedance/sonic v1.8.0 // indirect
  github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
  github.com/gin-contrib/sse v0.1.0 // indirect
  github.com/go-playground/locales v0.14.1 // indirect
  github.com/go-playground/universal-translator v0.18.1 // indirect
  github.com/go-playground/validator/v10 v10.11.2 // indirect
  github.com/goccy/go-json v0.10.0 // indirect
  github.com/json-iterator/go v1.1.12 // indirect
  github.com/klauspost/cpuid/v2 v2.0.9 // indirect
  github.com/leodido/go-urn v1.2.1 // indirect
  github.com/mattn/go-isatty v0.0.17 // indirect
  github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
  github.com/modern-go/reflect2 v1.0.2 // indirect
  github.com/pelletier/go-toml/v2 v2.0.6 // indirect
  github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
  github.com/ugorji/go/codec v1.2.9 // indirect
  golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
  golang.org/x/crypto v0.5.0 // indirect
  golang.org/x/net v0.7.0 // indirect
  golang.org/x/sys v0.5.0 // indirect
  golang.org/x/text v0.7.0 // indirect
  google.golang.org/protobuf v1.28.1 // indirect
  gopkg.in/yaml.v3 v3.0.1 // indirect
)

Dapat dilihat dibanding sebelumnya banyak hal, sekaligus akan menemukan ada file bernama go.sum di direktori

sh
$ ls
go.mod  go.sum  main.go

Di sini暂时 tidak dibahas, modifikasi file main.go menjadi kode berikut:

go
package main

import (
  "github.com/gin-gonic/gin"
)

func main() {
  gin.Default().Run()
}

Jalankan proyek lagi

sh
$ go run golearn
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080

Dengan demikian, melalui satu baris kode menjalankan web server paling sederhana. Saat tidak lagi membutuhkan dependensi tertentu, juga dapat menggunakan command go get untuk menghapus dependensi tersebut, di sini dengan menghapus Gin sebagai contoh

sh
$ go get github.com/gin-gonic/gin@none
go: removed github.com/gin-gonic/gin v1.9.0

Tambahkan @none di belakang alamat dependensi dapat menghapus dependensi tersebut, hasil juga memberitahu berhasil menghapus, saat ini lihat file go.mod lagi akan发现 tidak ada dependensi Gin.

sh
$ cat go.mod | grep github.com/gin-gonic/gin

Saat perlu upgrade ke versi terbaru, dapat menambahkan suffix @latest, atau dapat自行 query nomor versi Release yang tersedia

sh
$ go get -u github.com/gin-gonic/gin@latest

Instal Command Line

Command go install akan mendownload dependensi third-party ke lokal dan kompilasi menjadi file binary, berkat kecepatan kompilasi go, proses ini biasanya tidak memakan banyak waktu, lalu go akan menyimpannya di direktori $GOPATH/bin atau $GOBIN, agar dapat mengeksekusi file binary tersebut secara global (prasyarat Anda menambahkan path ini ke environment variable).

TIP

Saat menggunakan command install, harus menentukan nomor versi.

Misalnya mendownload debugger delve yang ditulis dalam bahasa go

bash
$ go install github.com/go-delve/delve/cmd/dlv@latest
go: downloading github.com/go-delve/delve v1.22.1
go: downloading github.com/cosiner/argv v0.1.0
go: downloading github.com/derekparker/trie v0.0.0-20230829180723-39f4de51ef7d
go: downloading github.com/go-delve/liner v1.2.3-0.20231231155935-4726ab1d7f62
go: downloading github.com/google/go-dap v0.11.0
go: downloading github.com/hashicorp/golang-lru v1.0.2
go: downloading golang.org/x/arch v0.6.0
go: downloading github.com/cpuguy83/go-md2man/v2 v2.0.2
go: downloading go.starlark.net v0.0.0-20231101134539-556fd59b42f6
go: downloading github.com/cilium/ebpf v0.11.0
go: downloading github.com/mattn/go-runewidth v0.0.13
go: downloading github.com/russross/blackfriday/v2 v2.1.0
go: downloading github.com/rivo/uniseg v0.2.0
go: downloading golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2

$ dlv -v
Error: unknown shorthand flag: 'v' in -v
Usage:
  dlv [command]

Available Commands:
  attach      Attach to running process and begin debugging.
  completion  Generate the autocompletion script for the specified shell
  connect     Connect to a headless debug server with a terminal client.
  core        Examine a core dump.
  dap         Starts a headless TCP server communicating via Debug Adaptor Protocol (DAP).
  debug       Compile and begin debugging main package in current directory, or the package specified.
  exec        Execute a precompiled binary, and begin a debug session.
  help        Help about any command
  test        Compile test binary and begin debugging program.
  trace       Compile and begin tracing program.
  version     Prints version.

Additional help topics:
  dlv backend    Help about the --backend flag.
  dlv log        Help about logging flags.
  dlv redirect   Help about file redirection.

Use "dlv [command] --help" for more information about a command.

Manajemen Modul

Semua konten di atas hanya讲述 penggunaan dasar Go Mod, tetapi sebenarnya untuk mempelajari Go Mod hanya ini sama sekali tidak cukup.官方 mendefinisikan modul sebagai: sekumpulan paket yang ditandai versi. Definisi di atas, paket seharusnya konsep yang sangat familiar, sedangkan versi harus mengikuti semantic versioning, didefinisikan sebagai: format v(major).(minor).(patch), misalnya versi Go v1.20.1, major version adalah 1, minor version adalah 20, patch version adalah 1, digabungkan menjadi v1.20.1, berikut adalah penjelasan lebih detail:

  • major: Saat major version berubah,说明 proyek terjadi perubahan yang tidak kompatibel, proyek versi lama upgrade ke versi baru kemungkinan besar tidak dapat berjalan normal.
  • minor: Saat minor version berubah,说明 proyek menambahkan fitur baru, hanya menambahkan fitur baru di basis versi sebelumnya.
  • patch: Saat patch version berubah,说明 hanya ada bug yang diperbaiki, tidak menambahkan fitur baru apa pun.

Command Umum

CommandPenjelasan
go mod downloadMendownload dependensi paket proyek saat ini
go mod editMengedit file go.mod
go mod graphOutput grafik dependensi modul
go mod initInisialisasi go mod di direktori saat ini
go mod tidyMembersihkan modul proyek
go mod verifyMemverifikasi legalitas dependensi proyek
go mod whyMenjelaskan di mana proyek menggunakan dependensi
go clean -modcacheDigunakan untuk menghapus cache dependensi modul proyek
go list -mMendaftarkan modul

前往 go mod cmd了解更多 informasi terkait command

Penyimpanan Modul

Saat menggunakan Go Mod untuk manajemen proyek, cache modul default disimpan di direktori $GOPATH/pkg/mod, juga dapat memodifikasi $GOMODCACHE untuk menentukan disimpan di lokasi lain.

sh
$ go env -w GOMODCACHE=path cache modul Anda

Semua proyek Go Module di mesin yang sama berbagi cache di direktori ini, cache tidak ada batasan ukuran dan tidak akan otomatis dihapus, source code dependensi yang di-extract di cache adalah read-only, ingin mengosongkan cache dapat jalankan command berikut.

sh
$ go clean -modcache

Di direktori $GOMODCACHE/cache/download menyimpan file asli dependensi, termasuk file hash, compressed package asli, dll, contoh berikut:

bash
$ ls $(go env GOMODCACHE)/cache/download/github.com/246859/hello/@v -1
list
v1.0.0.info
v1.0.0.lock
v1.0.0.mod
v1.0.0.zip
v1.0.0.ziphash

Struktur organisasi dependensi yang di-extract sebagai berikut, adalah source code modul yang ditentukan.

bash
$ ls $(go env GOMODCACHE)/github.com/246859/hello@v1.0.0 -1
LICENSE
README.md
cmd/
example/
go.mod
hello.go
hello_test.go

Pemilihan Versi

Go saat pemilihan versi dependensi, mengikuti prinsip pemilihan versi minimal. Berikut adalah contoh dari官网, modul utama mereferensikan versi 1.2 modul A dan versi 1.2 modul B, sekaligus versi 1.2 modul A mereferensikan versi 1.3 modul C, versi 1.2 modul B mereferensikan versi 1.4 modul C, dan versi 1.3 dan 1.4 modul C keduanya mereferensikan versi 1.2 modul D, menurut prinsip versi tersedia minimal, Go akhirnya akan memilih versi A1.2, B1.2, C1.4 dan D1.2.其中 biru muda表示 file go.mod yang dimuat, yang dibingkai表示 versi yang akhirnya dipilih.

官网 juga memberikan beberapa contoh lainnya, artinya hampir sama.

go.mod

Setiap membuat proyek Go Mod akan menghasilkan file go.mod, oleh karena itu familiar dengan file go.mod sangat perlu, tetapi sebagian besar kasus tidak perlu memodifikasi file go.mod secara manual.

module golearn

go 1.20

require github.com/gin-gonic/gin v1.9.0

require (
   github.com/bytedance/sonic v1.8.0 // indirect
   github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
   github.com/gin-contrib/sse v0.1.0 // indirect
   github.com/go-playground/locales v0.14.1 // indirect
   github.com/go-playground/universal-translator v0.18.1 // indirect
   github.com/go-playground/validator/v10 v10.11.2 // indirect
   github.com/goccy/go-json v0.10.0 // indirect
   github.com/json-iterator/go v1.1.12 // indirect
   github.com/klauspost/cpuid/v2 v2.0.9 // indirect
   github.com/leodido/go-urn v1.2.1 // indirect
   github.com/mattn/go-isatty v0.0.17 // indirect
   github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
   github.com/modern-go/reflect2 v1.0.2 // indirect
   github.com/pelletier/go-toml/v2 v2.0.6 // indirect
   github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
   github.com/ugorji/go/codec v1.2.9 // indirect
   golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
   golang.org/x/crypto v0.5.0 // indirect
   golang.org/x/net v0.7.0 // indirect
   golang.org/x/sys v0.5.0 // indirect
   golang.org/x/text v0.7.0 // indirect
   google.golang.org/protobuf v1.28.1 // indirect
   gopkg.in/yaml.v3 v3.0.1 // indirect
)

Di file dapat发现 sebagian besar alamat dependensi带有 kata seperti github dll, ini karena Go tidak memiliki repository dependensi publik, sebagian besar proyek open source di-hosting di Gitub, juga ada sebagian yang自行搭建 repository, misalnya google.golang.org/protobuf, golang.org/x/crypto. Biasanya, rangkaian网址 ini juga merupakan nama modul proyek Go, ini akan muncul masalah, URL tidak case-sensitive, tetapi folder penyimpanan dependensi case-sensitive, jadi go get github.com/gin-gonic/gin dan go get github.com/gin-gonic/Gin mereferensikan dependensi yang sama tetapi path penyimpanan lokal berbeda. Saat terjadi situasi ini, Go tidak langsung menggunakan huruf besar sebagai path penyimpanan, tetapi akan meng-escapenya menjadi !huruf kecil, misalnya github.com\BurntSushi akhirnya akan di-escape menjadi github.com\!burnt!sushi.

module

Keyword module mendeklarasikan nama modul proyek saat ini, satu file go.mod hanya boleh muncul satu keyword module. Contoh中的

module golearn

Mewakili nama modul saat ini adalah golearn, misalnya membuka file go.mod dependensi Gin dapat发现 nama modulenya

module github.com/gin-gonic/gin

Nama modul Gin adalah alamat yang digunakan saat mendownload dependensi, ini juga format nama modul yang direkomendasikan, domain/user/nama repository.

TIP

Ada satu hal yang perlu diperhatikan, saat major version lebih besar dari 1, nomor major version harus tercermin di nama modul, misalnya

github.com/my/example

Jika versi upgrade ke v2.0.0, maka nama modul perlu dimodifikasi menjadi berikut

github.com/my/example/v2

Jika proyek原有 mereferensikan versi lama, dan versi baru tidak membedakan, saat mereferensikan dependensi karena path sama, sehingga user tidak dapat membedakan perubahan major version yang带来的 perubahan tidak kompatibel, ini mungkin menyebabkan error program.

Deprecation

Komentar Deprecated di baris pertama atas module untuk表示 modul ini sudah di-deprecate, misalnya

// Deprecated: use example.com/mod/v2 instead.
module example.com/mod

go

Keyword go表示 versi Go yang digunakan untuk menulis proyek saat ini, nomor versi harus mengikuti aturan semantic versioning, sesuai versi go yang berbeda, Go Mod akan menunjukkan perilaku yang berbeda, berikut adalah contoh sederhana, tentang versi Go yang tersedia自行前往官方查阅.

go 1.20

require

Keyword require表示 mengimport dependensi eksternal, misalnya

require github.com/gin-gonic/gin v1.9.0

Formatnya adalah require nama_modul nomor_versi, saat ada banyak require dapat menggunakan kurung

require (
   github.com/bytedance/sonic v1.8.0 // indirect
)

Dengan komentar // indirect表示 dependensi ini tidak langsung direferensikan oleh proyek saat ini, mungkin dependensi yang direferensikan langsung proyek mereferensikan dependensi tersebut, jadi bagi proyek saat ini adalah indirect reference. Sebelumnya disebutkan saat major version berubah harus tercermin di nama modul, jika tidak mengikuti aturan ini modul disebut modul tidak standar, saat require, akan ditambahkan komentar incompatible.

require example.com/m v4.1.2+incompatible

Pseudo Version

Di file go.mod di atas, dapat发现 ada beberapa versi dependensi package bukan nomor versi semantic, tetapi string yang tidak jelas, ini sebenarnya adalah CommitID versi yang sesuai, versi semantic biasanya mengacu pada某一 Release. Nomor versi pseudo dapat diperkecil ke某一 Commit tertentu, format biasanya adalah vx.y.z-yyyyMMddHHmmss-CommitId, karena vx.y.znya tidak一定 benar ada, oleh karena itu disebut versi pseudo, misalnya v0.0.0 di contoh berikut tidak ada, yang benar-benar efektif adalah 12位 CommitID setelahnya.

// CommitID umumnya ambil 12位 pertama
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect

Demikian juga, saat mendownload dependensi juga dapat menentukan CommitID menggantikan nomor versi semantic

go get github.com/chenzhuoyu/base64x@fe3a3abad311

exclude

Keyword exclude表示 tidak memuat dependensi versi yang ditentukan, jika sekaligus ada require yang mereferensikan versi yang sama, juga akan diabaikan. Keyword ini hanya efektif di modul utama. Misalnya

exclude golang.org/x/net v1.2.3

exclude (
    golang.org/x/crypto v1.4.5
    golang.org/x/text v1.6.7
)

replace

replace akan menggantikan dependensi versi yang ditentukan, dapat menggunakan path modul dan versi untuk menggantikan atau path file yang ditentukan platform lain, contoh

text
replace golang.org/x/net v1.2.3 => example.com/fork/net v1.4.5

replace (
    golang.org/x/net v1.2.3 => example.com/fork/net v1.4.5
    golang.org/x/net => example.com/fork/net v1.4.5
    golang.org/x/net v1.2.3 => ./fork/net
    golang.org/x/net => ./fork/net
)

Hanya versi di sebelah kiri => yang digantikan, versi lain dari dependensi yang sama tetap dapat diakses normal, baik menggunakan path lokal atau path modul untuk menentukan penggantian, jika modul penggantian memiliki file go.mod, maka module directive-nya harus cocok dengan path modul yang digantikan.

retract

Directive retract表示, tidak boleh bergantung pada versi atau rentang versi dependensi yang ditentukan retract. Misalnya setelah merilis versi baru发现 ada masalah serius, saat ini dapat menggunakan directive retract.

Menarik kembali beberapa versi

text
retract (
    v1.0.0 // Published accidentally.
    v1.0.1 // Contains retractions only.
)

Menarik kembali rentang versi

text
retract v1.0.0
retract [v1.0.0, v1.9.9]
retract (
    v1.0.0
    [v1.0.0, v1.9.9]
)

go.sum

File go.sum saat awal membuat proyek tidak akan ada, hanya setelah benar-benar mengimport dependensi eksternal, baru akan menghasilkan file ini, file go.sum tidak cocok untuk dibaca manusia, juga tidak disarankan memodifikasi file ini secara manual. Fungsinya terutama untuk menyelesaikan masalah build yang konsisten, yaitu orang yang berbeda di lingkungan yang berbeda menggunakan proyek yang sama saat build dependensi package yang direferensikan harus sama persis, ini hanya mengandalkan satu file go.mod tidak dapat dijamin.

Selanjutnya lihat apa yang dilakukan Go dari awal sampai akhir saat mendownload dependensi, pertama gunakan command berikut untuk mendownload dependensi

go get github.com/bytedance/sonic v1.8.0

Command go get pertama akan mendownload dependensi package ke direktori cache lokal, biasanya direktori ini adalah $GOMODCACHE/cache/download/, direktori ini dibagi sesuai nama domain untuk dependensi website yang berbeda, jadi Anda mungkin melihat struktur direktori seperti berikut

sh
$ ls
cloud.google.com/      go.opencensus.io/     gopkg.in/          nhooyr.io/
dmitri.shuralyov.com/  go.opentelemetry.io/  gorm.io/           rsc.io/
github.com/            go.uber.org/          honnef.co/         sumdb/
go.etcd.io/            golang.org/           lukechampine.com/
go.mongodb.org/        google.golang.org/    modernc.org/

Maka path penyimpanan dependensi yang didownload pada contoh di atas terletak di

$GOMODCACHE/cache/download/github.com/bytedance/sonic/@v/

Struktur direktori yang mungkin sebagai berikut, akan ada beberapa file yang dinamai versi

sh
$ ls
list         v1.8.0.lock  v1.8.0.ziphash  v1.8.3.mod
v1.5.0.mod   v1.8.0.mod   v1.8.3.info     v1.8.3.zip
v1.8.0.info  v1.8.0.zip   v1.8.3.lock     v1.8.3.ziphash

Biasanya, di direktori ini pasti ada file list, digunakan untuk merekam nomor versi yang diketahui dari dependensi tersebut, dan untuk setiap versi, akan ada file seperti berikut:

  • zip: compressed package source code dependensi
  • ziphash: nilai hash yang dihitung berdasarkan compressed package dependensi
  • info: metadata versi format json
  • mod: file go.mod versi ini
  • lock: file temporary,官方 juga tidak mengatakan untuk apa

Umumnya, Go akan menghitung nilai hash dari dua file compressed package dan go.mod, lalu query nilai hash dependensi tersebut sesuai server yang ditentukan GOSUMDB (default adalah sum.golang.org), jika nilai hash yang dihitung lokal tidak konsisten dengan hasil query, maka tidak akan melanjutkan. Jika konsisten, akan update file go.mod, dan menyisipkan dua catatan ke file go.sum, kira-kira sebagai berikut:

github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA=
github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=

TIP

Jika GOSUMDB dinonaktifkan, Go akan langsung menulis nilai hash yang dihitung lokal ke file go.sum, umumnya tidak disarankan melakukan ini.

Normalnya setiap dependensi akan memiliki dua catatan, yang pertama adalah nilai hash compressed package, yang kedua adalah nilai hash file go.mod dependensi package, format catatan adalah nama_modul nomor_versi nama_algoritma:nilai_hash, beberapa dependensi package yang lebih tua mungkin tidak memiliki file go.mod, jadi tidak akan ada catatan hash kedua. Saat proyek ini di-build di lingkungan orang lain, Go akan menghitung nilai hash dependensi lokal yang ditentukan di go.mod, lalu bandingkan dengan nilai hash yang dicatat di go.sum, jika nilai hash tidak konsisten,说明 versi dependensi berbeda, akan menolak build. Saat terjadi situasi ini, dependensi lokal dan file go.sum keduanya mungkin telah dimodifikasi, tetapi karena file go.sum adalah catatan query GOSUMDB, jadi akan cenderung lebih percaya file go.sum.

Modul Privat

Sebagian besar tool Go Mod ditujukan untuk proyek open source, namun Go juga mendukung modul privat. Untuk proyek privat, biasanya perlu mengkonfigurasi beberapa environment configuration berikut untuk menangani modul privat

  • GOPROXY: kumpulan proxy server dependensi
  • GOPRIVATE: daftar pola umum prefix path modul privat, jika nama modul sesuai aturan表示 modul ini adalah modul privat, perilaku spesifik sama dengan GONOPROXY dan GONOSUMDB.
  • GONOPROXY: daftar pola umum prefix path modul yang tidak didownload dari proxy, jika sesuai aturan saat mendownload modul tidak akan lewat GOPROXY, coba langsung download dari version control system.
  • GONOSUMDB: daftar pola umum prefix path modul yang tidak melakukan validasi publik GOSUMDB, jika sesuai saat mendownload modul validasi tidak akan lewat database publik checksum.
  • GOINSECURE: daftar pola umum prefix path modul yang dapat diambil melalui HTTP dan protokol tidak aman lainnya.

Workspace

Sebelumnya disebutkan file go.mod mendukung directive replace, ini memungkinkan kita暂时 menggunakan modifikasi lokal yang belum sempat dirilis, sebagai berikut

replace (
  github.com/246859/hello v1.0.1 => ./hello
)

Saat kompilasi, go akan menggunakan modul hello lokal, setelah merilis versi baru di masa depan lalu hapus.

Tetapi jika menggunakan directive replace akan memodifikasi konten file go.mod, dan modifikasi ini mungkin salah submit ke repository remote, ini adalah hal yang tidak kita harapkan, karena target yang ditentukan directive replace adalah path file bukan URL network, path yang dapat digunakan di mesin ini mungkin tidak dapat digunakan di mesin lain, path file juga akan menjadi masalah besar dalam hal cross-platform. Untuk menyelesaikan masalah seperti ini, workspace pun muncul.

Workspace, adalah solusi baru tentang manajemen multi-modul yang diperkenalkan Go di 1.18, bertujuan untuk lebih baik melakukan pekerjaan pengembangan multi-modul lokal, berikut akan menjelaskan melalui contoh.

Repository contoh: 246859/work: go work example (github.com)

Contoh

Pertama di bawah proyek ada dua modul go independen, masing-masing adalah auth, user

bash
$ ls -1
LICENSE
README.md
auth
go.work
user

Modul auth bergantung pada struct User dari modul user, konten sebagai berikut

go
package auth

import (
  "errors"
  "github.com/246859/work/user"
)

// Verify user credentials if is ok
func Verify(user user.User) (bool, error) {
  password, err := query(user.Name)
  if err != nil {
    return false, err
  }
  if password != user.Password {
    return false, errors.New("authentication failed")
  }
  return true, nil
}

func query(username string) (string, error) {
  if username == "jack" {
    return "jack123456", nil
  }
  return "", errors.New("user not found")
}

Konten modul user sebagai berikut

go
package user

type User struct {
  Name     string
  Password string
  Age      int
}

Di proyek ini, kita dapat menulis file go.work seperti ini

go 1.22

use (
  ./auth
  ./user
)

Kontennya sangat mudah dipahami, menggunakan directive use, menentukan modul mana yang berpartisipasi dalam kompilasi, selanjutnya jalankan kode di modul auth

go
// auth/example/main.go
package main

import (
  "fmt"
  "github.com/246859/work/auth"
  "github.com/246859/work/user"
)

func main() {
  ok, err := auth.Verify(user.User{Name: "jack", Password: "jack123456"})
  if err != nil {
    panic(err)
  }
  fmt.Printf("%v", ok)
}

Jalankan command berikut, dari hasil得知 berhasil mengimport modul.

bash
$ go run ./auth/example
true

Di versi sebelumnya, untuk dua modul independen ini, jika modul auth ingin menggunakan kode dari modul user hanya ada dua cara

  1. Submit modifikasi modul user dan push ke repository remote, rilis versi baru, lalu modifikasi file go.mod menjadi versi yang ditentukan
  2. Modifikasi file go.mod redirect dependensi ke file lokal

Kedua cara perlu memodifikasi file go.mod, dan keberadaan workspace adalah untuk dapat mengimport modul lain tanpa memodifikasi file go.mod. Namun perlu dipahami satu hal, file go.work hanya digunakan selama pengembangan, keberadaannya hanya untuk lebih nyaman melakukan pengembangan lokal, bukan untuk manajemen dependensi, ia hanya暂时 membuat Anda melewatkan proses submit ke rilis, memungkinkan Anda segera menggunakan modifikasi baru modul user tanpa harus menunggu, saat modul user test selesai, terakhir tetap perlu merilis versi baru, dan modul auth terakhir tetap harus memodifikasi file go.mod untuk mengimport versi terbaru (proses ini dapat diselesaikan dengan command go work sync), oleh karena itu selama proses pengembangan go normal, go.work juga tidak boleh submit ke VCS (file go.work di repository contoh hanya untuk demonstrasi), karena kontennya bergantung pada file lokal, dan fungsinya juga terbatas pada pengembangan lokal.

Command

Berikut adalah beberapa command workspace

CommandPenjelasan
editMengedit go.work
initMenginisialisasi workspace baru
syncMensinkronkan dependensi modul workspace
useMenambahkan modul baru ke go.work
vendorMenyalin dependensi sesuai format vendor

前往 go work cmd了解更多 informasi terkait command

Directive

Konten file go.work sangat sederhana, hanya tiga directive

  • go, menentukan versi go
  • use, menentukan modul yang digunakan
  • replace, menentukan modul yang digantikan

Selain directive use, dua lainnya pada dasarnya setara dengan directive di go.mod, hanya saja directive replace di go.work akan berlaku untuk semua modul, satu go.work lengkap sebagai berikut.

tex
go 1.22

use(
  ./auth
  ./user
)

repalce github.com/246859/hello v1.0.0 => /home/jack/code/hello

Golang by www.golangdev.cn edit