Skip to content

Module

ภาษาสมัยใหม่ทุกภาษามีเครื่องมือจัดการการพึ่งพาที่เป็นของตัวเอง เช่น Gradle ของ Java, Pip ของ Python, Npm ของ NodeJs เป็นต้น เครื่องมือจัดการการพึ่งพาที่ดีสามารถประหยัดเวลาให้ผู้พัฒนาได้มากและเพิ่มประสิทธิภาพการพัฒนา อย่างไรก็ตาม Go ในช่วงแรกไม่มีโซลูชันจัดการการพึ่งพาที่เป็นผู้ใหญ่那时所有的โค้ดทั้งหมดเก็บอยู่ในไดเรกทอรี GOPATH ซึ่งไม่เป็นมิตรสำหรับโปรเจกต์วิศวกรรม เวอร์ชันสับสน การพึ่งพาจัดการยาก เพื่อแก้ปัญหานี้ นักพัฒนาในชุมชนต่างๆ แย่งชิงกัน สถานการณ์วุ่นวายในช่วงเวลานั้น ในช่วงเวลานั้นก็มีผู้โดดเด่นเช่น Vendor เกิดขึ้น จนกระทั่ง Go1.11 ทางการ推出 Go Mod เครื่องมือจัดการการพึ่งพาทางการ ยุติสถานการณ์วุ่นวายก่อนหน้า และ不断完善ในการอัปเดตต่อมา ตัดเครื่องมือเก่าที่เคยมีออก จนถึงปัจจุบัน ขณะเขียนบทความนี้ เวอร์ชัน Go ถึง 1.20 แล้ว วันนี้เกือบทุกโปรเจกต์ Go ใช้ Go Mod ดังนั้นในบทความนี้จะแนะนำเฉพาะ Go Mod ทางการยังเขียนเอกสารที่ละเอียดมากสำหรับโมดูล Go: Go Modules Reference

การเขียนโมดูล

Go Module โดยพื้นฐานแล้วอยู่บน VCS (ระบบควบคุมเวอร์ชัน) เมื่อคุณดาวน์โหลดการพึ่งพา ที่จริงแล้วกำลังดำเนินการคำสั่ง VCS เช่น git ดังนั้นหากคุณต้องการแชร์ไลบรารีที่คุณเขียน เพียงทำตามสามข้อต่อไปนี้:

  • ที่เก็บซอร์สโค้ดสามารถเข้าถึงได้สาธารณะ และ VCS เป็นหนึ่งในต่อไปนี้
    • git
    • hg (Mercurial)
    • bzr (Bazaar)
    • svn
    • fossil
  • เป็นโปรเจกต์ go mod ที่符合มาตรฐาน -符合มาตรฐานเวอร์ชันความหมาย

ดังนั้นคุณเพียงใช้ VCS พัฒนาตามปกติ และสร้าง Tag ที่符合มาตรฐานสำหรับเวอร์ชันเฉพาะของคุณ ผู้อื่นสามารถดาวน์โหลดไลบรารีที่คุณเขียนผ่านชื่อโมดูล ต่อไปนี้จะแสดงตัวอย่างเพื่อสาธิตขั้นตอนการพัฒนาโมดูลหลายขั้นตอน

ที่เก็บตัวอย่าง: 246859/hello: say hello (github.com)

การเตรียมการ

ก่อนเริ่มต้น ตรวจสอบให้แน่ใจว่าเวอร์ชันของคุณรองรับ go mod อย่างสมบูรณ์ (go >= 1.17) และเปิดใช้งาน Go Module แล้ว ตรวจสอบว่าเปิดใช้งานหรือไม่ผ่านคำสั่งต่อไปนี้

bash
$ go env GO111MODULE

หากยังไม่เปิดใช้งาน เปิดใช้งาน Go Module ผ่านคำสั่งต่อไปนี้

bash
$ go env -w GO111MODULE=on

การสร้าง

ก่อนอื่นคุณต้องการที่เก็บซอร์สโค้ดที่สามารถเข้าถึงได้สาธารณะ มีตัวเลือกมากมาย ฉันแนะนำ Github สร้างโปรเจกต์ใหม่บนนั้น ตั้งชื่อว่า hello ชื่อที่เก็บแม้ไม่มีข้อจำกัดพิเศษ แต่แนะนำให้ไม่ใช้ตัวอักษรพิเศษ เพราะจะส่งผลต่อชื่อโมดูล

หลังจากสร้างเสร็จแล้ว จะเห็น URL ของที่เก็บคือ https://github.com/246859/hello ชื่อโมดูล go ที่สอดคล้องกันคือ github.com/246859/hello

จากนั้นโคลนมันไปยังเครื่องท้องถิ่น เริ่มต้นโมดูลผ่านคำสั่ง 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

การเขียน

จากนั้นสามารถเริ่มการพัฒนาได้ ฟังก์ชันของมันง่ายมาก มีเพียงฟังก์ชันเดียว

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)
}

顺便เขียนไฟล์ทดสอบสำหรับการทดสอบหน่วย

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)
        }

}

ต่อไปเขียนโปรแกรม command line สำหรับ输出 hello ฟังก์ชันของมันง่ายมากเช่นกัน สำหรับโปรแกรม command line ตามมาตรฐานควรสร้างใน cmd/app_name/ ของโปรเจกต์ ดังนั้นไฟล์โปรแกรม command line hello เก็บอยู่ในไดเรกทอรี cmd/hello/ จากนั้นเขียนโค้ดที่เกี่ยวข้อง在其中

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())
  }
}

การทดสอบ

หลังจากเขียนเสร็จ จัดรูปแบบซอร์สโค้ดและทดสอบ

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

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

รันโปรแกรม command line

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

เอกสาร

สุดท้าย ต้องเขียน README ที่กระชับและชัดเจนสำหรับไลบรารีนี้ ให้ผู้พัฒนาคนอื่น看一眼就知道怎么ใช้

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)
}
```

นี่เป็นเอกสาร README ที่ง่ายมาก คุณสามารถเพิ่มเติมได้เอง

การอัปโหลด

เมื่อโค้ดทั้งหมดเขียนและทดสอบเสร็จแล้ว สามารถส่งการแก้ไขและผลักดันไปยังที่เก็บระยะไกล

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(-)

ทั้งหมดหก commit ไม่มาก หลังจากส่งเสร็จแล้ว สร้าง tag สำหรับ commit ล่าสุด

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

สุดท้ายผลักดันไปยังที่เก็บระยะไกล

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

หลังจากผลักดันเสร็จแล้ว สร้าง release สำหรับมัน (มี tag ก็เพียงพอแล้ว release เป็นเพียง符合มาตรฐาน github)

เช่นนี้ การเขียนโมดูลก็เสร็จแล้ว นี่คือขั้นตอนพื้นฐานของการพัฒนาโมดูล ผู้พัฒนาคนอื่นสามารถนำเข้าโค้ดหรือติดตั้งเครื่องมือ command line ผ่านชื่อโมดูล

การนำเข้า

นำเข้าไลบรารีผ่าน 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

ติดตั้งโปรแกรม command line ผ่าน go install

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

หรือใช้ go run รันโดยตรง

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

เมื่อไลบรารีถูกนำเข้าแล้ว Go Package จะสร้างหน้าสำหรับมัน กระบวนการนี้ทำโดยอัตโนมัติ ไม่ต้องให้ผู้พัฒนาทำอะไร เช่น ไลบรารี hello มีหน้าเอกสารเฉพาะ如下图所示

สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับการอัปโหลดโมดูล ไปที่ Add a package

สำหรับข้อมูลเกี่ยวกับวิธีการลบโมดูล ไปที่ Removing a package

การตั้งค่าพร็อกซี

Go แม้ไม่มีคลังกลางเช่น Maven Repo, PyPi, NPM แต่มีคลังพร็อกซีทางการ: Go modules services (golang.org)它将缓存โมดูลที่ผู้พัฒนาดาวน์โหลดตามเวอร์ชันและชื่อโมดูล อย่างไรก็ตามเนื่องจากเซิร์ฟเวอร์部署อยู่ในต่างประเทศ ความเร็วการเข้าถึงไม่เป็นมิตรสำหรับผู้ใช้ในประเทศ ดังนั้นเราต้องแก้ไขที่อยู่พร็อกซีโมดูลเริ่มต้น ปัจจุบันในประเทศมี以下几家ที่ทำได้ดี:

ที่นี่เลือกพร็อกซีของ七牛云 ดำเนินการคำสั่งต่อไปนี้เพื่อแก้ไขพร็อกซี Go ในนั้น directหมายถึงหลังจากดาวน์โหลดผ่านพร็อกซีล้มเหลว ข้าม缓存พร็อกซีเข้าถึงที่เก็บซอร์สโค้ดโดยตรง

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

หลังจากแก้ไขพร็อกซีสำเร็จแล้ว การดาวน์โหลดการพึ่งพาในอนาคตจะรวดเร็วมาก

การดาวน์โหลดการพึ่งพา

หลังจากแก้ไขพร็อกซีแล้ว ต่อไปลองติดตั้งการพึ่งพาบุคคลที่สาม Go ทางการมีเว็บไซต์ค้นหาการพึ่งพาเฉพาะ: Go Packages

การนำเข้าโค้ด

ค้นหาเฟรมเวิร์ก Web ที่มีชื่อเสียง Gin ในนั้น

ที่นี่จะปรากฏผลลัพธ์การค้นหาจำนวนมาก เมื่อใช้การพึ่งพาบุคคลที่สาม ต้องพิจารณาจำนวนการนำเข้าและเวลาอัปเดตเพื่อตัดสินใจว่าใช้การพึ่งพานี้หรือไม่ ที่นี่เลือก第一个โดยตรง

หลังจากเข้าสู่หน้า соответствующแล้ว จะเห็นว่าเป็นหน้าเอกสารของการพึ่งพานี้ มีข้อมูลรายละเอียดมากมายเกี่ยวกับมัน เมื่อ查阅เอกสารในภายหลังก็สามารถมาที่นี่ได้

ที่นี่เพียงคัดลอกที่อยู่ของมัน下来 แล้วใช้คำสั่ง go get ในโปรเจกต์ที่สร้างก่อนหน้า คำสั่งดังนี้

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

ในระหว่างกระบวนการจะดาวน์โหลดการพึ่งพาจำนวนมาก เพียงไม่มีข้อผิดพลาดแสดงว่าดาวน์โหลดสำเร็จ

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

หลังจากเสร็จแล้วดูไฟล์ 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
)

จะเห็นว่าเมื่อเทียบกับก่อนมี很多东西เพิ่มขึ้น และจะพบว่าในไดเรกทอรีมีไฟล์ชื่อ go.sum เพิ่มมา

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

ที่นี่暂且不表 แก้ไขไฟล์ main.go เป็นโค้ดดังนี้:

go
package main

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

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

รันโปรเจกต์อีกครั้ง

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

ดังนั้น ผ่านโค้ดหนึ่งบรรทัดก็รันเซิร์ฟเวอร์ Web ที่ง่ายที่สุดได้ เมื่อไม่ต้องการการพึ่งพา某一个อีกต่อไป ก็สามารถใช้คำสั่ง go get เพื่อลบการพึ่งพานั้นได้ ที่นี่以ลบ Gin เป็นตัวอย่าง

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

เพิ่ม @none หลังที่อยู่การพึ่งพาก็สามารถลบการพึ่งพานั้นได้ ผลลัพธ์ก็提示ว่าลบสำเร็จ เวลาดูไฟล์ go.mod อีกครั้งจะพบว่าไม่มี依赖 Gin แล้ว

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

เมื่อต้องการอัปเกรดเป็นเวอร์ชันล่าสุด สามารถเพิ่ม后缀 @latest หรือสามารถค้นหาหมายเลขเวอร์ชัน Release ที่可用ได้เอง

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

การติดตั้ง command line

คำสั่ง go install จะดาวน์โหลดการพึ่งพาบุคคลที่สามไปยังเครื่องท้องถิ่นและคอมไพล์เป็นไฟล์ไบนารี得益于ความเร็วการคอมไพล์ของ go กระบวนการนี้通常ไม่ใช้เวลามาก แล้ว go จะเก็บมันไว้ในไดเรกทอรี $GOPATH/bin หรือ $GOBIN เพื่อให้สามารถ执行ไฟล์ไบนารีนี้ได้在全局 (前提是你将这些路径添加到了环境变量中)

TIP

เมื่อใช้คำสั่ง install ต้องระบุหมายเลขเวอร์ชัน

เช่นดาวน์โหลดดีบักเกอร์ที่เขียนด้วยภาษา go delve

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.

การจัดการโมดูล

เนื้อหาทั้งหมดข้างต้นเป็นเพียง讲述การใช้งานพื้นฐานของ Go Mod แต่事实上要เรียนรู้ Go Mod เพียงเท่านี้ไม่เพียงพออย่างสมบูรณ์ ทางการให้นิยามของโมดูลว่า: ชุดของแพ็กเกจที่ถูกทำเครื่องหมายด้วยเวอร์ชัน ในนิยามข้างต้น แพ็กเกจควรเป็นแนวคิดที่คุ้นเคยมากแล้ว ส่วนเวอร์ชันต้องเป็นไปตามหมายเลขเวอร์ชันความหมาย นิยามว่า: รูปแบบ v(major).(minor).(patch) เช่น เวอร์ชัน Go v1.20.1 หมายเลขเวอร์ชันหลักคือ 1 หมายเลขเวอร์ชันรองคือ 20 หมายเลขเวอร์ชันแพตช์คือ 1 รวมกันคือ v1.20.1 ต่อไปนี้เป็นคำอธิบายที่ละเอียดขึ้น:

  • major: เมื่อเวอร์ชัน major เปลี่ยนแปลง แสดงว่าโปรเจกต์มีการเปลี่ยนแปลงที่ไม่เข้ากัน โปรเจกต์เวอร์ชันเก่าอัปเกรดเป็นเวอร์ชันใหม่大概率无法运行ได้ปกติ
  • minor: เมื่อเวอร์ชัน minor เปลี่ยนแปลง แสดงว่าโปรเจกต์เพิ่มคุณสมบัติใหม่ เพียงเพิ่มฟังก์ชันใหม่บนพื้นฐานของเวอร์ชันก่อนหน้า
  • patch: เมื่อเวอร์ชัน patch เปลี่ยนแปลง แสดงว่าเพียงมี bug ถูกแก้ไข ไม่เพิ่มฟังก์ชันใหม่ใดๆ

คำสั่งที่ใช้บ่อย

คำสั่งคำอธิบาย
go mod downloadดาวน์โหลดแพ็กเกจการพึ่งพาของโปรเจกต์ปัจจุบัน
go mod editแก้ไขไฟล์ go.mod
go mod graphแสดงกราฟการพึ่งพาโมดูล
go mod initเริ่มต้น go mod ในไดเรกทอรีปัจจุบัน
go mod tidyทำความสะอาดโมดูลโปรเจกต์
go mod verifyตรวจสอบความถูกต้องของการพึ่งพาโปรเจกต์
go mod whyอธิบายว่าโปรเจกต์ใช้การพึ่งพาที่ไหนบ้าง
go clean -modcacheใช้สำหรับลบ缓存การพึ่งพาโมดูลโปรเจกต์
go list -mแสดงรายการโมดูล

ไปที่ go mod cmd เพื่อ了解ข้อมูลเพิ่มเติมเกี่ยวกับคำสั่ง

การเก็บโมดูล

เมื่อใช้ Go Mod สำหรับการจัดการโปรเจกต์缓存โมดูล默认存放在ไดเรกทอรี $GOPATH/pkg/mod หรือสามารถแก้ไข $GOMODCACHE เพื่อ指定存放在ตำแหน่งอื่น

sh
$ go env -w GOMODCACHE=路径缓存โมดูลของคุณ

โปรเจกต์ Go Module ทั้งหมดบนเครื่องเดียวกันใช้缓存ในไดเรกทอรีนี้ร่วมกัน缓存ไม่มีข้อจำกัดขนาดและไม่ลบโดยอัตโนมัติ ไฟล์ซอร์สการพึ่งพาที่解压ใน缓存เป็นแบบอ่านอย่างเดียว หากต้องการล้าง缓存สามารถ执行คำสั่งต่อไปนี้

sh
$ go clean -modcache

ในไดเรกทอรี $GOMODCACHE/cache/download เก็บไฟล์ต้นฉบับของการพึ่งพา รวมถึงไฟล์แฮช ไฟล์压缩包ต้นฉบับ เป็นต้น เช่นตัวอย่าง:

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

รูปแบบการจัด组织การพึ่งพาหลัง解压เป็นดังนี้ คือซอร์สโค้ดของโมดูลที่指定

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

การเลือกเวอร์ชัน

Go เมื่อเลือกเวอร์ชันการพึ่งพา ปฏิบัติตามหลักการเลือกเวอร์ชันต่ำสุด ต่อไปนี้เป็นตัวอย่างจากเว็บไซต์หลัก โมดูลหลักนำเข้าเวอร์ชัน 1.2 ของโมดูล A และเวอร์ชัน 1.2 ของโมดูล B ในขณะเดียวกันเวอร์ชัน 1.2 ของโมดูล A นำเข้าเวอร์ชัน 1.3 ของโมดูล C เวอร์ชัน 1.2 ของโมดูล B นำเข้าเวอร์ชัน 1.4 ของโมดูล C และเวอร์ชัน 1.3 และ 1.4 ของโมดูล C ต่างนำเข้าเวอร์ชัน 1.2 ของโมดูล D ตามหลักการเวอร์ชันที่ใช้ได้ต่ำสุด Go จะเลือกเวอร์ชันสุดท้ายคือ A1.2, B1.2, C1.4 และ D1.2 ในนั้นสีฟ้าอ่อนแสดงว่าโหลดโดยไฟล์ go.mod ส่วนที่框选แสดงเวอร์ชันที่เลือกสุดท้าย

เว็บไซต์หลักยังให้ ตัวอย่างอื่นๆ อีกหลายตัวอย่าง ความหมาย大体差不多

go.mod

ทุกครั้งที่สร้างโปรเจกต์ Go Mod จะสร้างไฟล์ go.mod ดังนั้นการ熟悉ไฟล์ go.mod จึงจำเป็นอย่างยิ่ง แต่ส่วนใหญ่ไม่จำเป็นต้องแก้ไขไฟล์ 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
)

ในไฟล์จะพบว่าที่อยู่การพึ่งพาส่วนใหญ่มีคำว่า github เป็นต้น นี่เป็นเพราะ Go ไม่มีคลังการพึ่งพาสาธารณะ โปรเจกต์โอเพนซอร์สส่วนใหญ่โฮสต์บน Github มีบางส่วนที่สร้างคลังเอง เช่น google.golang.org/protobuf, golang.org/x/crypto โดยปกติแล้ว ชุดของ网址นี้同时也是ชื่อโมดูลของโปรเจกต์ Go ซึ่งจะทำให้เกิดปัญหาหนึ่ง URL ไม่แยกตัวพิมพ์ใหญ่เล็ก แต่โฟลเดอร์ที่เก็บการพึ่งพาแยกตัวพิมพ์ใหญ่เล็ก ดังนั้น go get github.com/gin-gonic/gin และ go get github.com/gin-gonic/Gin สองอย่างนี้อ้างอิงถึงการพึ่งพาเดียวกันแต่路径ที่เก็บในท้องถิ่นต่างกัน เมื่อเกิด这种情况ขึ้น Go ไม่直接把ตัวอักษรใหญ่เป็น路径ที่เก็บ แต่จะแปลงเป็น !ตัวอักษรเล็ก เช่น github.com\BurntSushi สุดท้ายจะแปลงเป็น github.com\!burnt!sushi

module

คำสำคัญ module ประกาศชื่อโมดูลของโปรเจกต์ปัจจุบัน ในไฟล์ go.mod หนึ่งไฟล์สามารถปรากฏคำสำคัญ module ได้เพียงหนึ่งคำเท่านั้น ในตัวอย่าง

module golearn

แสดงว่าชื่อโมดูลปัจจุบันคือ golearn เช่นเปิดไฟล์ go.mod ของการพึ่งพา Gin จะพบชื่อ module ของมัน

module github.com/gin-gonic/gin

ชื่อโมดูลของ Gin คือที่อยู่ที่ใช้เมื่อดาวน์โหลดการพึ่งพา นี่ก็เป็นรูปแบบชื่อโมดูลที่แนะนำโดยทั่วไป โดเมน/ผู้ใช้/ชื่อที่เก็บ

TIP

มีข้อควรระวังหนึ่งคือ เมื่อเวอร์ชันหลักมากกว่า 1 หมายเลขเวอร์ชันหลักต้องปรากฏในชื่อโมดูล เช่น

github.com/my/example

หากเวอร์ชันอัปเกรดเป็น v2.0.0 แล้ว ชื่อโมดูลต้องแก้ไขเป็นดังนี้

github.com/my/example/v2

หากโปรเจกต์เดิมอ้างอิงเวอร์ชันเก่า และเวอร์ชันใหม่ไม่แยกแยะ เมื่ออ้างอิงการพึ่งพาเนื่องจาก路径一致 ดังนั้นผู้ใช้ไม่สามารถแยกแยะการเปลี่ยนแปลงที่ไม่เข้ากันที่เกิดจากการเปลี่ยนแปลงเวอร์ชันหลัก เช่นนี้อาจทำให้โปรแกรมผิดพลาด

Deprecation

注释 Deprecated ที่บรรทัดแรกของ module เพื่อแสดงว่าโมดูลนี้ถูกยกเลิกแล้ว เช่น

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

go

คำสำคัญ go แสดงเวอร์ชัน Go ที่ใช้เขียนโปรเจกต์ปัจจุบัน หมายเลขเวอร์ชันต้องเป็นไปตามกฎความหมาย ตามเวอร์ชัน go ที่ต่างกัน Go Mod จะแสดงพฤติกรรมที่ต่างกัน ต่อไปนี้เป็นตัวอย่างง่ายๆ เกี่ยวกับหมายเลขเวอร์ชัน Go ที่可用โปรดไปที่ทางการเพื่อตรวจสอบ

go 1.20

require

คำสำคัญ require แสดงว่าอ้างอิงการพึ่งพาภายนอก เช่น

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

รูปแบบคือ require ชื่อโมดูล หมายเลขเวอร์ชัน เมื่อมีหลายการอ้างอิงสามารถใช้วงเล็บ括起来

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

ที่มี注释 // indirect แสดงว่าการพึ่งพานี้ไม่ถูกโปรเจกต์ปัจจุบันอ้างอิงโดยตรง อาจเป็นโปรเจกต์อ้างอิงการพึ่งพาโดยตรงอ้างอิงการพึ่งพานี้ ดังนั้นสำหรับโปรเจกต์ปัจจุบันจึงเป็นการอ้างอิงทางอ้อม ก่อนหน้า提到过当เวอร์ชันหลักเปลี่ยนแปลง时要体现在ชื่อโมดูล上 หากไม่ปฏิบัติตามกฎนี้โมดูล被称为โมดูลที่ไม่เป็นมาตรฐาน เมื่อ require时会加上注释 incompatible

require example.com/m v4.1.2+incompatible

เวอร์ชันปลอม

ในไฟล์ go.mod ด้านบน จะพบว่า有一些เวอร์ชันของแพ็กเกจการพึ่งพาไม่ใช่หมายเลขเวอร์ชันความหมาย แต่เป็นชุดของสตริงที่ไม่รู้เรื่อง นี่其实คือ CommitID ของเวอร์ชันนั้น เวอร์ชันความหมาย通常หมายถึง Release某一个 เวอร์ชันปลอมสามารถละเอียด到指定某一个 Commit โดยปกติรูปแบบคือ vx.y.z-yyyyMMddHHmmss-CommitId เนื่องจาก vx.y.z ของมันไม่一定มีอยู่จริง จึงเรียกว่าเวอร์ชันปลอม เช่นในตัวอย่างด้านล่าง v0.0.0 ไม่มีอยู่จริง ที่มีผลจริงคือ 12位 CommitID หลัง

// CommitID一般取前12位
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect

เช่นเดียวกัน เมื่อดาวน์โหลดการพึ่งพาก็สามารถ指定 CommitID แทนหมายเลขเวอร์ชันความหมายได้

go get github.com/chenzhuoyu/base64x@fe3a3abad311

exclude

คำสำคัญ exclude แสดงว่าไม่โหลดการพึ่งพาเวอร์ชันที่指定 หากมี require อ้างอิงเวอร์ชันเดียวกันในเวลาเดียวกัน ก็จะถูกเพิกเฉย คำสำคัญนี้มีผลเฉพาะในโมดูลหลักเท่านั้น เช่น

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 จะแทนที่การพึ่งพาเวอร์ชันที่指定 สามารถใช้路径โมดูลและเวอร์ชันแทนที่หรือเป็น路径ไฟล์ที่指定บนแพลตฟอร์มอื่น ตัวอย่าง

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
)

เฉพาะเวอร์ชันด้านซ้ายของ => ถูกแทนที่ เวอร์ชันอื่นของการพึ่งพาเดียวกันยังคงสามารถเข้าถึงได้ตามปกติ ไม่ว่าใช้路径ท้องถิ่นหรือ路径โมดูล指定แทนที่ หากโมดูลที่แทนที่มีไฟล์ go.mod แล้ว คำสั่ง module ของมันต้องตรงกับ路径โมดูลที่ถูกแทนที่

retract

คำสั่ง retract แสดงว่าไม่ควรพึ่งพาเวอร์ชันหรือช่วงเวอร์ชันของการพึ่งพาที่ retract指定 เช่นหลังจากเผยแพร่เวอร์ชันใหม่แล้วพบปัญหาสำคัญ这个时候就可以ใช้คำสั่ง retract

ถอนบางเวอร์ชัน

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

ถอนช่วงเวอร์ชัน

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

go.sum

ไฟล์ go.sum ในตอนเริ่มต้นการสร้างโปรเจกต์จะไม่มีอยู่ เฉพาะเมื่ออ้างอิงการพึ่งพาภายนอกจริงๆ จึงจะสร้างไฟล์นี้ขึ้น ไฟล์ go.sum ไม่เหมาะสำหรับการอ่านของมนุษย์ และไม่แนะนำให้แก้ไขไฟล์นี้ด้วยตนเอง หน้าที่ของมัน主要是แก้ปัญหาการสร้างที่สอดคล้องกัน คือคนที่ต่างกันใช้โปรเจกต์เดียวกันในการสร้างในสภาพแวดล้อมที่ต่างกัน การพึ่งพาที่อ้างอิงต้องเหมือนกันอย่างสมบูรณ์ เพียงไฟล์ go.mod ไฟล์เดียวไม่สามารถรับประกันได้

ต่อไปมาดูว่าเมื่อดาวน์โหลดการพึ่งพาหนึ่ง Go ทำอะไรตั้งแต่ต้นจนจบ ก่อนอื่นใช้คำสั่งต่อไปนี้ดาวน์โหลดการพึ่งพาหนึ่ง

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

คำสั่ง go get จะดาวน์โหลดแพ็กเกจการพึ่งพาไปยังไดเรกทอรี缓存ในท้องถิ่นก่อน โดยปกติไดเรกทอรีนั้นคือ $GOMODCACHE/cache/download/ ไดเรกทอรีนี้แบ่งการพึ่งพาของเว็บไซต์ต่างกันตามโดเมน ดังนั้นคุณอาจเห็นโครงสร้างไดเรกทอรีดังนี้

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/

ดังนั้น路径ที่เก็บการพึ่งพาที่ดาวน์โหลดในตัวอย่างข้างต้นอยู่ที่

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

โครงสร้างไดเรกทอรีที่เป็นไปได้เป็นดังนี้ จะมีไฟล์ที่ตั้งชื่อด้วยเวอร์ชันหลายไฟล์

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

โดยปกติแล้ว ในไดเรกทอรีนี้ต้องมีไฟล์ list หนึ่งไฟล์ ใช้บันทึกหมายเลขเวอร์ชันที่รู้จักของการพึ่งพานั้น และสำหรับแต่ละเวอร์ชัน จะมีไฟล์ดังนี้:

  • zip: ไฟล์压缩包ซอร์สโค้ดของการพึ่งพา
  • ziphash: ค่าแฮชที่คำนวณตามไฟล์压缩包ของการพึ่งพา
  • info: ข้อมูลเมตาเวอร์ชันรูปแบบ json
  • mod: ไฟล์ go.mod ของเวอร์ชันนี้
  • lock: ไฟล์ชั่วคราว ทางการก็ไม่บอกว่าใช้ทำอะไร

โดยทั่วไป Go จะคำนวณค่าแฮชของไฟล์压缩包และไฟล์ go.mod สองไฟล์ แล้ว查询ค่าแฮชของการพึ่งพานี้ตามเซิร์ฟเวอร์ที่ GOSUMDB指定 (默认คือ sum.golang.org) หากค่าแฮชที่คำนวณในท้องถิ่นไม่ตรงกับผลลัพธ์ที่ได้จากการ查询 แล้วจะไม่ดำเนินการต่อไปอีก หากตรงกัน จะอัปเดตไฟล์ go.mod และแทรกสองบันทึกเข้าไปในไฟล์ go.sum โดยประมาณดังนี้:

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

TIP

หากปิดใช้งาน GOSUMDB Go จะเขียนค่าแฮชที่คำนวณได้ในท้องถิ่นลงในไฟล์ go.sum โดยตรง โดยทั่วไปไม่แนะนำให้ทำเช่นนี้

โดยปกติแล้ว การพึ่งพาแต่ละรายการจะมีสองบันทึก แรกคือค่าแฮชของไฟล์压缩包 ที่สองคือค่าแฮชของไฟล์ go.mod ของแพ็กเกจการพึ่งพา รูปแบบบันทึกคือ ชื่อโมดูล หมายเลขเวอร์ชัน ชื่ออัลกอริทึม:ค่าแฮช บางแพ็กเกจการพึ่งพาที่เก่ามากอาจไม่มีไฟล์ go.mod ดังนั้นจะไม่มีบันทึกค่าแฮชที่สอง เมื่อโปรเจกต์นี้สร้างในสภาพแวดล้อมของอีกคน Go จะคำนวณค่าแฮชของการพึ่งพาในท้องถิ่นตาม ที่ไฟล์ go.mod指定 แล้วเปรียบเทียบ กับค่าแฮชที่บันทึกในไฟล์ go.sum หากค่าแฮชไม่ตรงกัน แสดงว่าเวอร์ชันการพึ่งพาต่างกัน จะปฏิเสธการสร้าง เมื่อเกิด这种情况ขึ้น การพึ่งพาในท้องถิ่นและไฟล์ go.sum ต่างอาจถูกแก้ไขได้ แต่เนื่องจาก go.sum ผ่านการ查询บันทึกของ GOSUMDB ดังนั้นจะ傾向相信ไฟล์ go.sum มากกว่า

โมดูลส่วนตัว

เครื่องมือ Go Mod ส่วนใหญ่是针对โปรเจกต์โอเพนซอร์ส แต่ Go ก็รองรับโมดูลส่วนตัวด้วย สำหรับโปรเจกต์ส่วนตัว โดยปกติแล้วต้องกำหนดค่าการตั้งค่าสภาพแวดล้อมต่อไปนี้เพื่อจัดการโมดูลส่วนตัว

  • GOPROXY: ชุดเซิร์ฟเวอร์พร็อกซีของการพึ่งพา
  • GOPRIVATE: รายการรูปแบบทั่วไปของคำนำหน้า路径โมดูลของโมดูลส่วนตัว หากชื่อโมดูล符合กฎแสดงว่าโมดูลนี้เป็นโมดูลส่วนตัว พฤติกรรมเฉพาะเหมือนกับ GONOPROXY และ GONOSUMDB
  • GONOPROXY: รายการรูปแบบทั่วไปของคำนำหน้า路径โมดูลที่ไม่ดาวน์โหลดจากพร็อกซี หาก符合กฎเมื่อดาวน์โหลดโมดูลจะไม่ผ่าน GOPROXY พยายามดาวน์โหลดจากระบบควบคุมเวอร์ชันโดยตรง
  • GONOSUMDB: รายการรูปแบบทั่วไปของคำนำหน้า路径โมดูลที่ไม่ตรวจสอบสาธารณะ GOSUMDB หาก符合เมื่อดาวน์โหลดโมดูลตรวจสอบจะไม่ผ่านฐานข้อมูลสาธารณะของ checksum
  • GOINSECURE: รายการรูปแบบทั่วไปของคำนำหน้า路径โมดูลที่สามารถ检索ผ่าน HTTP และโปรโตคอลที่ไม่ปลอดภัยอื่นๆ

Workspace

ก่อนหน้า提到过ไฟล์ go.mod รองรับคำสั่ง replace ซึ่งทำให้เราสามารถใช้การแก้ไขในท้องถิ่นที่来不及เผยแพร่ได้ชั่วคราว ดังนี้

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

เมื่อคอมไพล์ go จะใช้โมดูล hello ในท้องถิ่น หลังจากเผยแพร่เวอร์ชันใหม่ในอนาคตจึงลบออก

แต่หากใช้คำสั่ง replace จะแก้ไขเนื้อหาของไฟล์ go.mod และการแก้ไขนี้อาจถูกส่งไปยังที่เก็บระยะไกลโดยไม่ได้ตั้งใจ这是我们不希望看到的 เพราะ target ที่คำสั่ง replace指定เป็น路径ไฟล์而非 URL เครือข่าย路径ที่ใช้ได้ในเครื่องนี้อาจใช้ไม่ได้ในเครื่องอื่น路径ไฟล์ยังเป็นปัญหาใหญ่ในด้านการข้ามแพลตฟอร์ม เพื่อแก้ปัญหาดังกล่าว workspace จึงเกิดขึ้น

Workspace เป็นโซลูชันใหม่เกี่ยวกับการจัดการหลายโมดูลที่ Go นำเข้าใน 1.18 มุ่งหมายเพื่อทำการพัฒนาหลายโมดูลในท้องถิ่นได้ดีขึ้น ต่อไปนี้จะอธิบายผ่านตัวอย่างหนึ่ง

ที่เก็บตัวอย่าง: 246859/work: go work example (github.com)

ตัวอย่าง

ก่อนอื่นโปรเจกต์มีโมดูล go อิสระสองโมดูล分别是 auth, user

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

โมดูล auth พึ่งพา struct User ของโมดูล user เนื้อหาเป็นดังนี้

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")
}

เนื้อหาโมดูล user เป็นดังนี้

go
package user

type User struct {
  Name     string
  Password string
  Age      int
}

ในโปรเจกต์นี้ เราสามารถเขียนไฟล์ go.work ดังนี้

go 1.22

use (
  ./auth
  ./user
)

เนื้อหาของมันเข้าใจง่ายมาก ใช้คำสั่ง use指定ว่าโมดูลใดเข้าร่วมการคอมไพล์ ต่อไปรันโค้ดในโมดูล 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)
}

รันคำสั่งต่อไปนี้ ผ่านผลลัพธ์得知นำเข้าโมดูลสำเร็จ

bash
$ go run ./auth/example
true

ในเวอร์ชันก่อนหน้า สำหรับสองโมดูลอิสระนี้ หากโมดูล auth ต้องการใช้โค้ดในโมดูล user มีเพียงสองวิธี

  1. ส่งการแก้ไขของโมดูล user และผลักดันไปยังที่เก็บระยะไกล เผยแพร่เวอร์ชันใหม่ แล้วแก้ไขไฟล์ go.mod เป็นเวอร์ชันที่指定
  2. แก้ไขไฟล์ go.mod เพื่อเปลี่ยนการพึ่งพาไปยังไฟล์ในท้องถิ่น

สองวิธี都需要แก้ไขไฟล์ go.mod และการมีอยู่ของ workspace ก็เพื่อให้สามารถนำเข้าโมดูลอื่นได้โดยไม่ต้องแก้ไขไฟล์ go.mod แต่ต้องเข้าใจอย่างหนึ่งคือ ไฟล์ go.work ใช้เฉพาะในระหว่างการพัฒนาเท่านั้น การมีอยู่ของมัน只是为了ทำการพัฒนาในท้องถิ่นได้สะดวกขึ้น而非สำหรับการจัดการการพึ่งพา มัน只是暂时让你略过การส่งไปยังการเผยแพร่นี้ คุณสามารถใช้การแก้ไขใหม่ของโมดูล user ได้ทันทีโดยไม่ต้องรอ เมื่อโมดูล user ทดสอบเสร็จแล้ว สุดท้ายยังต้องเผยแพร่เวอร์ชันใหม่ และโมดูล auth สุดท้ายยังต้องแก้ไขไฟล์ go.mod เพื่ออ้างอิงเวอร์ชันล่าสุด (กระบวนการนี้สามารถใช้คำสั่ง go work sync เพื่อ完成) ดังนั้นในกระบวนการพัฒนา go ปกติ go.work ก็ไม่ควรส่งไปยัง VCS ( go.work ในที่เก็บตัวอย่างใช้สำหรับการสาธิตเท่านั้น) เพราะเนื้อหาของมันพึ่งพาไฟล์ในท้องถิ่น และหน้าที่ของมันก็จำกัดเฉพาะการพัฒนาในท้องถิ่นเท่านั้น

คำสั่ง

ต่อไปนี้เป็นคำสั่ง workspace บางคำสั่ง

คำสั่งคำอธิบาย
editแก้ไข go.work
initเริ่มต้น workspace ใหม่
syncซิงค์การพึ่งพาโมดูลของ workspace
useเพิ่มโมดูลใหม่เข้าไปใน go.work
vendorคัดลอกการพึ่งพาตามรูปแบบ vendor

ไปที่ go work cmd เพื่อ了解ข้อมูลเพิ่มเติมเกี่ยวกับคำสั่ง

คำสั่ง

เนื้อหาของไฟล์ go.work ง่ายมาก มีเพียงสามคำสั่ง

  • go指定เวอร์ชัน go
  • use指定โมดูลที่ใช้
  • replace指定โมดูลที่แทนที่

นอกจากคำสั่ง use แล้ว อีกสองคำสั่ง基本上เหมือนกับคำสั่งใน go.mod เพียงแต่คำสั่ง replace ใน go.work จะกระทำกับโมดูลทั้งหมด go.work ที่สมบูรณ์เป็นดังนี้

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