Dòng lệnh

Các lệnh trong Go bao gồm một bộ công cụ hoàn chỉnh, các lệnh này涵盖 tài liệu, định dạng, kiểm tra mã, biên dịch, kiểm thử, quản lý phụ thuộc và nhiều khía cạnh khác của phát triển Go.
bug Báo cáo lỗi
build Biên dịch gói và các phụ thuộc
clean Xóa các tệp đối tượng
doc Hiển thị tài liệu trong mã nguồn
env Xem thông tin biến môi trường Go
fix Sửa các vấn đề tương thích API do thay đổi phiên bản go
fmt Định dạng mã nguồn
generate Tạo mã
get Thêm phụ thuộc
install Cài đặt và biên dịch gói
list Lệnh liệt kê gói/mô-đun
mod Lệnh bảo trì mô-đun
work Lệnh bảo trì vùng làm việc
run Biên dịch và chạy
test Kiểm thử
tool Chạy công cụ go được chỉ định
version Hiển thị thông tin phiên bản go
vet Quét và hiển thị các vấn đề tiềm ẩn trong mã nguồnBài viết này chỉ đơn giản trình bày và giới thiệu cách sử dụng của chúng, tất cả nội dung tham khảo từ tài liệu chính thức, nếu muốn tìm hiểu thêm chi tiết có thể truy cập cmd/go.
help
Lệnh đầu tiên cần biết là lệnh help, thông qua nó có thể đọc cách sử dụng của các lệnh. Có hai cách sử dụng, nếu muốn lấy thông tin sử dụng ngắn gọn, có thể thêm cờ -h sau lệnh được chỉ định, ví dụ
$ go env -h
usage: go env [-json] [-u] [-w] [var ...]
Run 'go help env' for details.go sẽ hiển thị ngắn gọn cách sử dụng của lệnh đó, nó cũng提示 rằng muốn lấy thông tin chi tiết hơn cần sử dụng lệnh help
$ go help env
usage: go env [-json] [-u] [-w] [var ...]
Env prints Go environment information.
By default env prints information as a shell script
(on Windows, a batch file). If one or more variable
names is given as arguments, env prints the value of
each named variable on its own line.
The -json flag prints the environment in JSON format
instead of as a shell script.
The -u flag requires one or more arguments and unsets
the default setting for the named environment variables,
if one has been set with 'go env -w'.
The -w flag requires one or more arguments of the
form NAME=VALUE and changes the default settings
of the named environment variables to the given values.
For more about environment variables, see 'go help environment'.Sử dụng thành thạo lệnh help, thông qua nó bạn có thể lấy nhiều thông tin liên quan đến lệnh.
doc
$ go doc -h
Usage of [go] doc:
go doc
go doc <pkg>
go doc <sym>[.<methodOrField>]
go doc [<pkg>.]<sym>[.<methodOrField>]
go doc [<pkg>.][<sym>.]<methodOrField>
go doc <pkg> <sym>[.<methodOrField>]
For more information run
go help doc
Flags:
-C dir
change to dir before running command
-all
show all documentation for package
-c symbol matching honors case (paths not affected)
-cmd
show symbols with package docs even if package is a command
-short
one-line representation for each symbol
-src
show source code for symbol
-u show unexported symbols as well as exportedLệnh doc sẽ xuất tài liệu chú thích của gói, hằng số, hàm, kiểu, biến, phương thức và thậm chí cả trường cấu trúc được chỉ định. Khi không có tham số nào, nó sẽ xuất chú thích của gói hiện tại
$ go docCũng có thể chỉ định xem một gói nào đó, ví dụ xem tài liệu chú thích của gói runtime
$ go doc runtime
package runtime // import "runtime"
Package runtime contains operations that interact with Go's runtime system,
such as functions to control goroutines. It also includes the low-level type
information used by the reflect package; see reflect's documentation for the
programmable interface to the run-time type system.
......Hoặc một kiểu nào đó
$ go doc unsafe.Pointer
package unsafe // import "unsafe"
type Pointer *ArbitraryType
Pointer represents a pointer to an arbitrary type. There are four special
operations available for type Pointer that are not available for other
types:
- A pointer value of any type can be converted to a Pointer.
- A Pointer can be converted to a pointer value of any type.
- A uintptr can be converted to a Pointer.
- A Pointer can be converted to a uintptr.
...Hoặc một hàm nào đó
$ go doc runtime.GC
package runtime // import "runtime"
func GC()
GC runs a garbage collection and blocks the caller until the garbage
collection is complete. It may also block the entire program.Nó có các cờ常用 sau
-u: Xem các kiểu riêng tư-all: Xem tất cả tài liệu của gói được chỉ định-short: Chỉ hiển thị mô tả ngắn gọn một dòng-src: Xuất mã nguồn-cmd: Đối với một số gói thuộc lệnh go, cũng xuất tài liệu mã trong gói của chúng.
Ví dụ xem biến runtime.inf, đây là một biến không được export
$ go doc -u runtime.inf
package runtime // import "runtime"
var inf = float64frombits(0x7FF0000000000000)Sử dụng tốt lệnh doc có thể giúp bạn đọc tài liệu thuận tiện hơn.
Một cách khác để đọc tài liệu lệnh là đọc mã nguồn, bởi vì tài liệu của một số lệnh không được viết kỹ lưỡng, ngược lại trong mã nguồn sẽ có giải thích chi tiết hơn. Vì tất cả các lệnh này đều được viết bằng go, nên việc đọc cũng rất thuận tiện. Các lệnh này đều nằm trong gói src/cmd, mỗi gói con là một lệnh riêng, entry point nằm trong tệp cmd/go/main.go
func init() {
base.Go.Commands = []*base.Command{
bug.CmdBug,
work.CmdBuild,
clean.CmdClean,
doc.CmdDoc,
envcmd.CmdEnv,
fix.CmdFix,
fmtcmd.CmdFmt,
generate.CmdGenerate,
modget.CmdGet,
work.CmdInstall,
list.CmdList,
modcmd.CmdMod,
workcmd.CmdWork,
run.CmdRun,
test.CmdTest,
tool.CmdTool,
version.CmdVersion,
vet.CmdVet,
help.HelpBuildConstraint,
help.HelpBuildmode,
help.HelpC,
help.HelpCache,
help.HelpEnvironment,
help.HelpFileType,
modload.HelpGoMod,
help.HelpGopath,
get.HelpGopathGet,
modfetch.HelpGoproxy,
help.HelpImportPath,
modload.HelpModules,
modget.HelpModuleGet,
modfetch.HelpModuleAuth,
help.HelpPackages,
modfetch.HelpPrivate,
test.HelpTestflag,
test.HelpTestfunc,
modget.HelpVCS,
}
}Ở đây bạn sẽ tìm thấy tất cả các lệnh con của go, cũng như thông tin tài liệu trợ giúp của chúng.
bug
$ go help bug
usage: go bug
Bug opens the default browser and starts a new bug report.
The report includes useful system information.Lệnh này không có tham số và cờ nào, nó sẽ dùng trình duyệt mặc định của bạn để truy cập trang issue của kho lưu trữ github.com/golang/go, thuận tiện cho bạn phản hồi bug, ngoài ra không có chức năng nào khác.
version
Thông qua lệnh version có thể xem thông tin phiên bản go hiện tại.
$ go version -h
usage: go version [-m] [-v] [file ...]Khi thực thi không có tham số nào, nó sẽ xuất phiên bản go hiện tại
$ go version
go version go1.21.0 windows/amd64Nó cũng nhận đường dẫn tệp làm tham số, nó sẽ xuất phiên bản go được sử dụng khi biên dịch tất cả các tệp nhị phân có thể nhận dạng được trong đường dẫn đó.
$ go version -v ./
buf.exe: go1.20.2
cobra-cli.exe: go1.21.0
dlv.exe: go1.20.2
goctl.exe: go1.20.2
goimports.exe: go1.20.2
golangci-lint.exe: go1.20.2
gopls.exe: go1.19.3
kratos.exe: go1.20.2
main.exe: go1.19.1
protoc-gen-go-grpc.exe: go1.20.2
protoc-gen-go-http.exe: go1.20.2
protoc-gen-go.exe: go1.20.2
protoc-gen-openapi.exe: go1.20.2
swag.exe: go1.21.0
wire.exe: go1.21.0Trong đó tham số -v chỉ định lệnh version thử xuất phiên bản go của các tệp không thể nhận dạng, tham số -m xuất thông tin mô-đun của tệp nhị phân, cũng như một số tham số biên dịch, dưới đây là một ví dụ đơn giản.
$ go version -v -m wire.exe
wire.exe: go1.21.0
path github.com/google/wire/cmd/wire
mod github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
dep github.com/google/subcommands v1.0.1 h1:/eqq+otEXm5vhfBrbREPCSVQbvofip6kIz+mX5TUH7k=
dep github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
dep golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b h1:NVD8gBK33xpdqCaZVVtd6OFJp+3dxkXuz7+U7KaVN6s=
build -buildmode=exe
build -compiler=gc
build DefaultGODEBUG=panicnil=1
build CGO_ENABLED=1
build CGO_CFLAGS=
build CGO_CPPFLAGS=
build CGO_CXXFLAGS=
build CGO_LDFLAGS=
build GOARCH=amd64
build GOOS=windows
build GOAMD64=v1Bản thân go cũng là một tệp nhị phân, thực ra trong trường hợp không có tham số nào, go version xuất chính phiên bản go của tệp nhị phân của nó, vì tất cả các công cụ của cmd/go đều được triển khai bằng chính ngôn ngữ go.
env
Thông qua lệnh env có thể xem tất cả thông tin biến môi trường go, việc thay đổi các biến môi trường này sẽ ảnh hưởng đến hành vi của công cụ go.
$ go env -h
usage: go env [-json] [-u] [-w] [var ...]
Run 'go help env' for details.Thực thi lệnh này không có tham số nào sẽ xuất giá trị của tất cả biến môi trường go
$ go env
set GO111MODULE=on
set GOARCH=amd64
...Đưa tên một biến môi trường nào đó làm tham số có thể chỉ xuất giá trị của biến đó
$ go env GO111MODULE
onThêm -json có thể xuất dưới dạng json
$ go env -json
{
"AR": "ar",
"CC": "gcc",
......
}Thông qua cờ -w, và dùng dạng var=value làm tham số, sẽ thay đổi vĩnh viễn giá trị của một biến nào đó
$ go env -w GO111MODULE=onSử dụng cờ -u, có thể khôi phục một biến nào đó về giá trị mặc định
$ go env -u GO111MODULEThực thi go help environment có thể xem giới thiệu của từng biến môi trường
$ go help environment
The go command and the tools it invokes consult environment variables
for configuration. If an environment variable is unset or empty, the go
command uses a sensible default setting. To see the effective setting of
the variable <NAME>, run 'go env <NAME>'. To change the default setting,
run 'go env -w <NAME>=<VALUE>'. Defaults changed using 'go env -w'
are recorded in a Go environment configuration file stored in the
per-user configuration directory, as reported by os.UserConfigDir.
The location of the configuration file can be changed by setting
the environment variable GOENV, and 'go env GOENV' prints the
effective location, but 'go env -w' cannot change the default location.
See 'go help env' for details.
General-purpose environment variables:
GO111MODULE
Controls whether the go command runs in module-aware mode or GOPATH mode.
May be "off", "on", or "auto".
See https://golang.org/ref/mod#mod-commands.
GCCGO
The gccgo command to run for 'go build -compiler=gccgo'.
GOARCH
The architecture, or processor, for which to compile code.
Examples are amd64, 386, arm, ppc64.
GOBIN
The directory where 'go install' will install a command.
GOCACHE
The directory where the go command will store cached
information for reuse in future builds.
......Dưới đây giới thiệu một số biến môi trường常用
GOVERSION
Giá trị của biến môi trường này phụ thuộc vào phiên bản go, và số phiên bản đến từ tệp $GOROOT/VERSION, tệp này ghi lại phiên bản go hiện tại và thời gian build.
$ cat $GOROOT/VERSION
go1.21.3
time 2023-10-09T17:04:35ZGiá trị của biến runtime.Version giống với giá trị của GOVERSION, và biến môi trường này không thể bị thay đổi.
GOENV
Trong thư mục $GOROOT sẽ có một tệp cấu hình mặc định tên là go.env
$ cat $GOROOT/go.env
# This file contains the initial defaults for go command configuration.
# Values set by 'go env -w' and written to the user's go/env file override these.
# The environment overrides everything else.
# Use the Go module mirror and checksum database by default.
# See https://proxy.golang.org for details.
GOPROXY=https://proxy.golang.org,direct
GOSUMDB=sum.golang.org
# Automatically download newer toolchains as directed by go.mod files.
# See https://go.dev/doc/toolchain for details.
GOTOOLCHAIN=autoĐịnh dạng của nó đơn giản là key=value, giá trị biến môi trường được thay đổi bằng lệnh go env -w key=value sẽ được ghi vào tệp cấu hình. Tuy nhiên cũng có thể không dùng tệp cấu hình mặc định, biến môi trường GOENV có thể chỉ định thủ công địa chỉ tệp cấu hình env, và giá trị của biến môi trường GOENV chỉ có thể bị ghi đè bởi biến môi trường hệ điều hành, không thể bị thay đổi bằng lệnh go env -w.
GOHOSTARCH
Đại diện cho kiến trúc CPU của máy này, chỉ dùng để hiển thị, giá trị của biến môi trường này không được đọc từ tệp cấu hình và cũng không thể bị thay đổi.
GOHOSTOS
Đại diện cho hệ điều hành của máy này, chỉ dùng để hiển thị, giá trị của biến môi trường này không được đọc từ tệp cấu hình và cũng không thể bị thay đổi.
GOOS
Khi biên dịch, giá trị của GOOS sẽ quyết định biên dịch mã nguồn thành tệp nhị phân của hệ thống mục tiêu nào, giá trị mặc định là GOHOSTOS, tức là hệ điều hành của máy này, nó có các tùy chọn sau
linuxdarwinwindowsnetbsdaixandroid
Thực tế các hệ điều hành được hỗ trợ không chỉ có这些, sử dụng lệnh go tool dist list, xem tất cả các giá trị được hỗ trợ
$ go tool dist list | awk -F '/' '{print $1}' | awk '!seen[$0]++'
aix
android
darwin
dragonfly
freebsd
illumos
ios
js
linux
netbsd
openbsd
plan9
solaris
wasip1
windowsGOARCH
Khi biên dịch, giá trị của GOARCH sẽ quyết định sử dụng kiến trúc CPU nào khi biên dịch, giá trị mặc định là GOHOSTARCH, tức là kiến trúc CPU của máy này, nó có các tùy chọn sau
amd64386armppc64
Thực tế các kiến trúc được hỗ trợ không chỉ có这些, sử dụng lệnh go tool dist list, xem tất cả các giá trị được hỗ trợ
$ go tool dist list | awk -F '/' '{print $2}' | awk '!seen[$0]++'
ppc64
386
amd64
arm
arm64
riscv64
wasm
loong64
mips
mips64
mips64le
mipsle
ppc64le
s390xCần lưu ý rằng GOOS và GOARCH không thể kết hợp tùy ý, một số hệ điều hành chỉ có thể hỗ trợ các kiến trúc CPU cụ thể.
GOROOT
GOROOT đại diện cho thư mục gốc của vị trí cài đặt go, giá trị của GOROOT không thể bị thay đổi trực tiếp và chỉ có thể bị ghi đè bởi biến môi trường hệ điều hành.
$ ls $GOROOT -1
api
bin
codereview.cfg
CONTRIBUTING.md
doc
go.env
lib
LICENSE
misc
PATENTS
pkg
README.md
SECURITY.md
src
test
VERSIONTrong thư mục gốc có một số thư mục hoặc tệp quan trọng sau
lib, chứa một số phụ thuộc, hiện tại chỉ có một thư viện chứa thông tin múi giờ của các quốc gia trên thế giới, nằm trong$GOROOT/lib/time, các tệp nhị phân sau khi biên dịch sẽ không chứa thông tin múi giờ này.pkg, chứa một số thư viện công cụ và tệp tiêu đề, ví dụ lệnhgo toolsẽ tìm kiếm các tệp nhị phân của công cụ go trong thư mục$GOROOT/pkg/toolbin, chứa các tệp nhị phân, mặc định chỉ có các tệp thực thigovàgofmt,$GOROOT/binnên được thêm vào biến hệ thống, nếu không sẽ không thể sử dụng các lệnh go.src, chứa mã nguồn goVERSION, tệp này chứa thông tin phiên bản của gogo.env, tệp này là tệp cấu hìnhenvmặc định
GOPATH
Giá trị mặc định của GOPATH là $HOME/go, giá trị của biến môi trường này chỉ định nơi tìm kiếm các tệp được import khi phân tích cú pháp câu lệnh import. Trong thời kỳ đầu không có gomod, GOPATH được dùng专门 để chứa các thư viện bên thứ ba, cấu trúc của nó như sau
GOPATH=/home/user/go
/home/user/go/
src/
foo/
bar/ (go code in package bar)
x.go
quux/ (go code in package main)
y.go
bin/
quux (installed command)
pkg/
linux_amd64/
foo/
bar.a (installed package object)Sau khi gomod ra đời, GOPATH chỉ là nơi chứa các phụ thuộc được tải xuống bằng go get, cũng như dùng để chứa các tệp nhị phân được tải xuống và biên dịch bằng go install. Cần lưu ý rằng vị trí của GOPATH không thể giống với GOROOT, nếu không sẽ không có tác dụng gì.
$ go env GOBIN
warning: GOPATH set to GOROOT (/home/user/go) has no effectTính đến thời điểm笔者 viết bài này, phiên bản go đã là go1.21.3, ngoài các dự án rất cũ, hầu như không ai còn dùng gopath để quản lý phụ thuộc nữa.
GOBIN
GOBIN dùng để chứa các tệp thực thi nhị phân bên thứ ba được tải xuống và biên dịch bằng go install, giá trị mặc định của nó là $GOPATH/bin. Giống như $GOROOT/bin, thư mục này nên được thêm vào biến môi trường hệ điều hành, nếu không cũng sẽ không thể sử dụng các tệp nhị phân trong thư mục GOBIN.
GOMODCACHE
GOMODCACHE biểu thị vị trí chứa các phụ thuộc được tải xuống bằng go get, giá trị mặc định là $GOPATH/pkg/mod. Định dạng lưu trữ của nó như sau
$GOMODCACHE/domain/username/project@verionTrong cùng cấp thư mục sẽ có một thư mục tên là sumdb, dùng để chứa thông tin liên quan đến cơ sở dữ liệu checksum phụ thuộc.
GOCACHE
Chứa thông tin cache dùng cho biên dịch, giá trị mặc định của nó là $HOME/.cache/go-build, trong thư mục này sẽ tạo một tệp README.
$ cat $(go env GOCACHE)/README
This directory holds cached build artifacts from the Go build system.
Run "go clean -cache" if the directory is getting too large.
Run "go clean -fuzzcache" to delete the fuzz cache.
See golang.org to learn more about Go.Mỗi lần build sẽ tạo ra nhiều tệp, go sẽ cache các tệp này để tái sử dụng khi biên dịch lần sau.
GOTEMPDIR
Dùng cho các tệp tạm thời phát sinh khi biên dịch, ví dụ tệp nhị phân tạm thời cần chạy bằng go run. Giá trị mặc định của nó là thư mục tạm thời được chỉ định bởi hệ điều hành, trên mac hoặc linux là /tmp, trên windows là %TEMP%, cũng có thể thay đổi thành vị trí được chỉ định bởi người dùng.
GO111MODULE
Biến môi trường này biểu thị sử dụng cách nào để quản lý phụ thuộc của dự án go, có ba giá trị khả dụng sau
off, tắt gomod, dùng gopath, và sẽ bỏ qua tất cả các tệpgo.modon, dùng gomod, không dùng gopath (mặc định).auto, tự động nhận biết, nếu tệp dự án chứago.modsẽ dùng gomod để quản lý
TIP
Tại sao gọi là GO111MODULE, không gọi trực tiếp là GOMODULE, vì gomod được giới thiệu lần đầu trong phiên bản go1.11.
GOPROXY
Proxy mô-đun go, giá trị mặc định là https://proxy.golang.org,direct, url được phân tách bằng dấu phẩy, direct nghĩa là trực tiếp dùng VCS bỏ qua proxy mô-đun, chỉ khi cái trước không thể truy cập mới thực thi cái sau, còn một tùy chọn khả dụng khác là off, biểu thị cấm tải xuống bất kỳ mô-đun nào. Ngoài ra, GOPROXY cũng có thể là địa chỉ tệp, ví dụ
GOPROXY=file://$(go env GOMODCACHE)/cache/downloadThông qua go get -x có thể xem các lệnh được thực thi trong quá trình tải xuống phụ thuộc, từ đó biết có dùng proxy hay không.
$ go get -x github.com/spf13/cast
# get https://goproxy.cn/github.com/@v/list
# get https://goproxy.cn/github.com/spf13/cast/@v/list
# get https://goproxy.cn/github.com/spf13/@v/list
# get https://goproxy.cn/github.com/spf13/@v/list: 404 Not Found (0.118s)
# get https://goproxy.cn/github.com/@v/list: 404 Not Found (0.197s)
# get https://goproxy.cn/github.com/spf13/cast/@v/list: 200 OK (0.257s)
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.info
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.info: 200 OK (0.013s)
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.mod
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.mod: 200 OK (0.015s)
# get https://goproxy.cn/sumdb/sum.golang.org/supported
# get https://goproxy.cn/sumdb/sum.golang.org/supported: 200 OK (0.064s)
# get https://goproxy.cn/sumdb/sum.golang.org/lookup/github.com/spf13/cast@v1.5.1
# get https://goproxy.cn/sumdb/sum.golang.org/lookup/github.com/spf13/cast@v1.5.1: 200 OK (0.014s)
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x079/736
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x079/736: 200 OK (0.016s)
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/1/266
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x068/334
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x068/334: 200 OK (0.023s)
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/1/266: 200 OK (0.028s)
go: downloading github.com/spf13/cast v1.5.1
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.zip
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.zip: 200 OK (0.024s)
go: added github.com/spf13/cast v1.5.1Sử dụng proxy mô-đun có thể nâng cao hiệu quả tải xuống mô-đun, người dùng trong nước về cơ bản nếu không dùng proxy sẽ không thể truy cập proxy mặc định của官方, hiện tại các proxy mô-đun bên thứ ba công khai và đáng tin cậy như sau
https://proxy.golang.com.cn, mã nguồn mở đồng thời cung cấp dịch vụ phiên bản doanh nghiệphttps://goproxy.cn, do Qiniu Cloud cung cấp và mã nguồn mở
Đương nhiên cũng có giải pháp tự xây dựng proxy mô-đun mã nguồn mở: goproxy
GOSUMDB
GOSUMDB dùng để thiết lập địa chỉ cơ sở dữ liệu phát hiện checksum của thư viện phụ thuộc, mặc định là sum.golang.org, khi bạn thiết lập proxy, go sẽ truy cập cơ sở dữ liệu checksum thông qua proxy.
GOPRIVATE
Biến môi trường GOPRIVATE dùng để thiết lập các kho riêng tư, các kho khớp sẽ không được xác minh qua sumdb và cũng không đi qua proxy, sẽ tải xuống phụ thuộc trực tiếp thông qua VCS. Hỗ trợ thiết lập ký tự đại diện, dùng dấu phẩy phân tách, như dưới đây, tất cả các phụ thuộc có hậu缀 là corp.example.com và tên là github.com/gohper/myproject sẽ không đi qua proxy và sumdb.
GOPRIVATE=*.corp.example.com,github.com/gohper/myprojectCũng có thể thiết lập trực tiếp một người dùng hoặc tổ chức nào đó
GOPRIVATE=github.com/gopher,github.com/myorganizationGONOPROXY
Biểu thị những phụ thuộc nào không cần đi qua proxy, quy tắc giống với GOPRIVATE, và sẽ ghi đè lên GOPRIVATE.
GONOSUMDB
Biểu thị những phụ thuộc nào không cần đi qua cơ sở dữ liệu checksum, quy tắc giống với GOPRIVATE, và sẽ ghi đè lên GOPRIVATE.
GOINSECURE
Biểu thị những phụ thuộc nào trực tiếp dùng VCS để tải xuống, quy tắc giống với GOPRIVATE, và sẽ bị ghi đè bởi GONOPROXY và GONOSUMDB.
GOVCS
Thiết lập hệ thống kiểm soát phiên bản của quản lý mô-đun, mặc định public:git|hg,private:all. Cũng có thể hạn chế VCS của tên miền được chỉ định, ví dụ
GOVCS=github.com:git,evil.com:off,*:git|hgTrong hạn chế trên, github chỉ có thể dùng git, evil.com thì không được phép, dùng | để biểu thị nhiều VCS. Nếu không thiết lập hạn chế nào, có thể thiết lập như sau
GOVCS=*:allNếu không cho phép sử dụng bất kỳ VCS nào, có thể thiết lập như sau
GOVCS=*:offGOWORK
Thiết lập xem có bật vùng làm việc hay không, mặc định là rỗng tức là bật, nếu thiết lập thành off, thì không bật, sẽ bỏ qua tất cả các tệp go.work.
GOTOOLDIR
Thiết lập vị trí của công cụ go cần sử dụng, mặc định là $GOROOT/pkg/tool, công cụ mặc định cũng được lưu trữ tại vị trí này.
GODEBUG
Thiết lập các tùy chọn gỡ lỗi, kiểm soát một phần hành vi thực thi của chương trình go dưới dạng cặp khóa-giá trị, ví dụ
GODEBUG=http2client=0,http2server=0Những thiết lập này là để thuận tiện khi go lùi về hành vi cũ khi có thay đổi không tương thích trong quá trình cập nhật phiên bản, ví dụ trong 1.21 không còn cho phép xảy ra tình huống panic(nil), vì vậy,官方 go đã ghi lại GODEBUG History, truy cập GODEBUG để biết thêm chi tiết.
CGO_ENABLED
Biểu thị có bật cgo hay không, mặc định là 1, tức là bật, thiết lập thành 0 thì tắt.
Những biến môi trường trên đều là những biến常用, đối với một số biến không常用 lắm sẽ không giới thiệu quá nhiều, như CGO, WASM và những thứ khác, nếu quan tâm có thể tự tìm hiểu.
build
Go hỗ trợ hai loại trình biên dịch, gccgo và gc. gcc là một trình biên dịch c/c++ lâu đời, hỗ trợ nhiều ngôn ngữ bao gồm go, gc sau này không phải là viết tắt của garbage collection, mà là go compiler, ngôn ngữ go đã hoàn thành self-hosting trong go1.5, gc là trình biên dịch được viết hoàn toàn bằng ngôn ngữ go, mã nguồn của nó nằm trong gói cmd/compile, vì được triển khai hoàn toàn bằng go nên cũng rất thuận tiện cho việc tìm hiểu và học tập cơ chế nội bộ của nó. Trong trường hợp mặc định, trình biên dịch sử dụng gc để biên dịch. Tiện thể nhắc một chút, trình gỡ lỗi go cũng chia làm hai loại, gdb và dlv, gdb là trình gỡ lỗi c/c++ lâu đời, hỗ trợ nhiều ngôn ngữ bao gồm go, dlv là trình gỡ lỗi được viết bằng ngôn ngữ go, hỗ trợ go thân thiện hơn, nó cũng là mã nguồn mở, khuyến nghị sử dụng cái sau. Lệnh build có tác dụng biên dịch các tệp nguồn go thành các tệp nhị phân có thể thực thi, bạn sẽ trải nghiệm khả năng biên dịch rất nhanh chóng, đây cũng chính là một trong những đặc điểm của ngôn ngữ go.
$ go build -h
usage: go build [-o output] [build flags] [packages]
Run 'go help build' for details.Nó nhận ba tham số, một là đường dẫn xuất tệp được chỉ định bởi cờ -o, hai là các cờ build dùng để định nghĩa hành vi biên dịch build flags, cuối cùng là gói cần biên dịch, tham số này phải đặt ở cuối. Dưới đây là một ví dụ đơn giản, không dùng đến cờ build.
# Windows
$ go build -o .\bin\golearn.exe golearn
# macOS / Linux
$ go build -o ./bin/golearn golearn./bin/golearn.exe biểu thị đường dẫn xuất, golearn biểu thị mô-đun cần biên dịch, cũng có thể là một tệp entry, hoặc một thư mục. Ví dụ dưới đây là một ví dụ đơn giản dùng tệp entry main.go làm mục tiêu biên dịch.
# Windows
$ go build -o .\bin\golearn.exe main.go
# macOS / Linux
$ go build -o ./bin/golearn main.goKhi biên dịch nó sẽ bỏ qua tất cả các tệp có đuôi _test.go, vì theo quy ước những tệp này đều là tệp kiểm thử.
Ngoài ra, lệnh build còn hỗ trợ khá nhiều cờ build dùng để kiểm soát một số hành vi khi biên dịch.
-x: Xuất các lệnh chi tiết trong quá trình biên dịch-n: Tương tự-x, nhưng khác biệt là nó chỉ xuất các lệnh này, nhưng thực tế sẽ không thực thi.-v: Xuất các gói được biên dịch-p: Số lượng đồng thời trong quá trình biên dịch-a: Bắt buộc build lại, ngay cả khi đã là mới nhất.-compiler: Chỉ định sử dụng trình biên dịch nào,gccgohoặcgc, cái sau là trình biên dịch được viết bằng go.-race: Bật phát hiện race condition-msan: Bật phân tích bộ nhớ-asan: Bật phân tích địa chỉ-cover: Bật phát hiện độ phủ mã-buildmode: Chỉ định chế độ biên dịch, có các tùy chọnarchive,c-archive,c-shared,default,shared,exe,pie,plugin.-pgo, chỉ định tệp pgo-trimpath: Loại bỏ tiền tố đường dẫn tệp nguồn, ví dụ đường dẫn tương đối/var/lib/go/src/main.go, sau khi loại bỏ thì thông quaruntime获取 được khi chạy chỉ còn đường dẫn tương đối so với đường dẫn mô-đun/main.go, sau khi bật mục này, thời gian biên dịch sẽ tăng rõ rệt, khoảng 20-40%左右, tùy thuộc vào số lượng tệp.-toolexec, một số lệnh go được thực thi trước khi biên dịch, định dạng là-toolexec 'cmd args'.-gcflags: Chỉ định một số tag của trình biên dịch gc-gccgoflags: Chỉ định một số tag của trình biên dịch gccgo-ldflags: Chỉ định một số tag của công cụ link
Đối với một số tham số truyền như ldflags, có thể truyền các tham số như "-help" để获取 các giá trị có thể có của nó, ví dụ
$ go build -ldflags -help
usage: link [options] main.o
-B note
add an ELF NT_GNU_BUILD_ID note when using ELF
-E entry
set entry symbol name
......Những điều trên là những thứ常用, đối với những thứ không常用 lắm có thể tự tìm hiểu.
gcflags
Thông qua gcflags có thể truyền một số tham số cho trình biên dịch gc để kiểm soát các hành vi cụ thể, định dạng sử dụng của nó là -gcflags="pattern=args list", args list là danh sách tham số, pattern là phạm vi tác dụng, có các giá trị khả dụng sau
main, đường dẫn gói cấp cao nhất nơi tệp entry nằmall, tất cả các phụ thuộc của mô-đun hiện tại và chế độ hiện tạistd, thư viện chuẩncmd, tác dụng lên tất cả các tệp nguồn trong góicmd- Ký tự đại diện, ví dụ
.,./...,cmd/....
Quy tắc pattern này áp dụng cho tất cả các cờ hỗ trợ định dạng này, ví dụ ldflags. Thông qua lệnh sau để xem các giá trị khả dụng của tham số
$ go build -gcflags -help
用法:compile [选项] file.go...
-% 调试非静态初始化器
-+ 编译运行时
-B 禁用边界检查
-C 禁用错误消息中的列号打印
-D path
设置本地导入的相对路径
-E 调试符号导出
-I directory
添加目录到导入搜索路径
-K 调试缺失的行号
-L 对于受 //line 指令影响的错误位置,同时显示实际源文件名
-N 禁用优化
-S 打印汇编列表
-V 打印版本并退出
-W 类型检查后调试解析树
......Dưới đây giới thiệu một số tham số常用
-S: Xuất dạng hợp ngữ của mã-N: Tắt tối ưu hóa biên dịch-m: Xuất quyết định tối ưu hóa-l: Tắt inline hàm-c: Số lượng đồng thời khi biên dịch-dwarf: Tạo ký hiệu DWARF
Ví dụ nếu muốn xem dạng hợp ngữ của mã, có thể sử dụng tham số -S, và còn phải tắt tối ưu hóa và inline, như vậy mới khôi phục được dạng gốc của nó, như sau
$ go build -trimpath -gcflags="-N -l -S" main.go
main.main STEXT size=171 args=0x0 locals=0x58 funcid=0x0 align=0x0
0x0000 00000 (./main.go:9) TEXT main.main(SB), ABIInternal, $88-0
0x0000 00000 (./main.go:9) CMPQ SP, 16(R14)
0x0004 00004 (./main.go:9) PCDATA $0, $-2
0x0004 00004 (./main.go:9) JLS 161
0x000a 00010 (./main.go:9) PCDATA $0, $-1
0x000a 00010 (./main.go:9) PUSHQ BP
0x000b 00011 (./main.go:9) MOVQ SP, BP
0x000e 00014 (./main.go:9) SUBQ $80, SP
0x0012 00018 (./main.go:9) FUNCDATA $0, gclocals·J5F+7Qw7O7ve2QcWC7DpeQ==(SB)
0x0012 00018 (./main.go:9) FUNCDATA $1, gclocals·bDfKCdmtOiGIuJz/x+yQyQ==(SB)
0x0012 00018 (./main.go:9) FUNCDATA $2, main.main.stkobj(SB)
0x0012 00018 (./main.go:10) MOVUPS X15, main..autotmp_0+40(SP)
0x0018 00024 (./main.go:10) LEAQ main..autotmp_0+40(SP), CX
0x001d 00029 (./main.go:10) MOVQ CX, main..autotmp_2+32(SP)ldflags
Thông qua ldflags có thể truyền một số tham số cho linker để kiểm soát các hành vi cụ thể, thông qua lệnh sau để xem tất cả các giá trị khả dụng của ldflags, gần hai ba mươi cái.
$ go build -ldflags -help
usage: link [options] main.o
-B note
add an ELF NT_GNU_BUILD_ID note when using ELF
-E entry
set entry symbol name
-H type
set header type
-I linker
use linker as ELF dynamic linker
-L directory
add specified directory to library path
-R quantum
set address rounding quantum (default -1)
-T int
set the start address of text symbols (default -1)
-V print version and exit
-X definition
add string value definition of the form importpath.name=value
-a no-op (deprecated)
.....Tham số -X của ldflags là một chức năng rất thiết thực, nó có thể định nghĩa giá trị của biến chuỗi của gói được chỉ định tại thời điểm link. Thông qua chức năng này, chúng ta có thể dễ dàng inject một số thông tin meta tại thời điểm biên dịch. Và nó chỉ là một biến, nên cũng thuận tiện cho việc获取 khi chạy, dưới đây là một ví dụ đơn giản.
package main
import "fmt"
var (
Version string
)
func main() {
fmt.Println(Version)
}Thực thi lệnh
go build -ldflags "-X main.Version=$(git describe --always)" main.goSau khi chạy sẽ xuất checksum sha1 của commit git.
5e3fd7aNgoài ra một số tham số thiết thực khác có
-w: Không tạo DWARF, đây là thông tin thuận tiện cho việc gỡ lỗi mã nguồn.-s: Tắt bảng ký hiệu
Hai cái này thường dùng cùng nhau, có thể giảm đáng kể kích thước của tệp nhị phân sau khi biên dịch, khoảng 40%-50%左右, nhược điểm cũng rất rõ ràng, không thể tiến hành gỡ lỗi, dưới đây là một ví dụ.
$ go build -ldflags="-w -s" main.goBiên dịch chéo
Biên dịch go luôn có hai đặc điểm lớn, một là nhanh, đặc điểm lớn còn lại là biên dịch chéo, biên dịch chéo đề cập đến việc có thể biên dịch thành mã mục tiêu của các hệ thống khác trên máy local, ví dụ trên windows biên dịch thành tệp nhị phân trên linux hoặc darwin, ngược lại cũng vậy. Biên dịch chéo hỗ trợ rất nhiều ngôn ngữ, đây không phải là điều hiếm gặp, nhưng biên dịch chéo của go rất đơn giản, chỉ cần hai bước sau
- Thiết lập biến môi trường GOOS, chọn hệ điều hành mục tiêu của bạn
- Thiết lập biến môi trường GOARCH, chọn kiến trúc CPU mục tiêu của bạn
- Sử dụng
go buildđể biên dịch như bình thường
Toàn bộ quá trình rất ngắn, không cần sử dụng công cụ hoặc cấu hình bổ sung, và tốc độ cũng nhanh như bình thường. Như dưới đây
build_linux:
SET CGO_ENABLED=0
SET GOOS="linux"
SET GOARCH="amd64"
go build -o golearn main.go
build_mac:
SET CGO_ENABLED=0
SET GOOS="darwin"
SET GOARCH="amd64"
go build -o golearn main.go
build_win:
SET CGO_ENABLED=0
SET GOOS="win"
SET GOARCH="amd64"
go build -o golearn.exe main.go
.PHONY: build_linux \
build_mac \
build_winBước đầu tiên SET CGO_ENABLED=0 tắt cgo, một khi mã của bạn sử dụng cgo, thì không thể sử dụng biên dịch chéo bình thường. Bước thứ hai SET GOOS thiết lập hệ thống mục tiêu, các tùy chọn có linux, darwin, windwos, netbsd. Bước thứ ba thiết lập kiến trúc CPU, SET GOARCH, các tùy chọn có amd64, 386, arm, ppc64. Bước cuối cùng là biên dịch như mọi khi.
Kiểm soát biên dịch
Lệnh build có thể đạt được hiệu quả kiểm soát biên dịch thông qua tags, nó tồn tại trong mã nguồn dưới dạng chỉ thị, xem một ví dụ, tệp product.go
// +build product
package main
import "fmt"
func main() {
fmt.Println("product")
}Tệp debug.go
// +build debug
package main
import "fmt"
func main() {
fmt.Println("debug")
}Chúng đều có một chỉ thị // +build, biểu thị chúng sẽ được biên dịch trong trường hợp nào. Định dạng cơ bản là
// +build tag1 tag2
package pkg_nameCó một số quy tắc bắt buộc phải tuân thủ
//và+buildphải cách nhau một khoảng trắng- Nó phải nằm trên khai báo gói
- Phải cách một dòng trống với khai báo gói
Ngoài ra, nó còn có thể đạt được mục đích kiểm soát logic thông qua khoảng cách đơn giản, khoảng trắng biểu thị OR, dấu phẩy biểu thị AND, ! biểu thị NOT. Ví dụ như ví dụ dưới đây
// +build windows linux
package pkg_nameBiểu thị rằng tệp hiện tại sẽ được biên dịch trên nền tảng windows hoặc linux.
// +build windows,amd64,!cgo linux,i386,cgo
package pkg_nameVí dụ này biểu thị rằng chỉ biên dịch khi là nền tảng windows kiến trúc amd64 và chưa bật cgo hoặc là nền tảng linux kiến trúc i386 và đã bật cgo. Nếu bạn chỉ đơn giản là không muốn một tệp nào đó tham gia biên dịch, có thể sử dụng ignore.
// +build ignore
package pkg_nameCũng có thể tồn tại nhiều dòng chỉ thị
// +build windows
// +build amd64
package pkg_nameNhiều dòng chỉ thị được xử lý theo cách AND. Đối với các tag như nền tảng và kiến trúc, go sẽ tự động truyền vào khi biên dịch, chúng ta cũng có thể truyền vào các tag tùy chỉnh, lấy hai tệp ban đầu làm ví dụ
$ go build -tags="debug" . && ./golearn.exe
debug
$ go build -tags="product" . && ./golearn.exe
productCó thể thấy khi truyền vào các tag khác nhau thì kết quả xuất khác nhau, mục đích kiểm soát biên dịch cũng đạt được.
run
Lệnh run và build đều sẽ biên dịch mã nguồn, khác biệt là lệnh run sẽ chạy trực tiếp sau khi biên dịch xong. Lệnh run để tăng tốc độ biên dịch, trong quá trình biên dịch sẽ không tạo thông tin gỡ lỗi, nên cũng không hỗ trợ gỡ lỗi, và chỉ tạo một tệp nhị phân tạm thời, thường được lưu trữ trong thư mục GOTMEPDIR, ví dụ /temp/go-build2822241271/b001/exe/main.exe.
$ go run -h
usage: go run [build flags] [-exec xprog] package [arguments...]
Run 'go help run' for details.Nó cũng hỗ trợ các cờ build của lệnh build, còn cung cấp một tham số -exec để chỉ định chương trình nào chạy tệp nhị phân, [arguments...] đề cập đến các tham số chạy của chương trình. Dưới đây là một ví dụ
package main
import (
"fmt"
"os"
)
var (
Version string
)
func main() {
fmt.Println(Version)
fmt.Println(os.Args[1:])
}Sử dụng go run để chạy
$ go run -ldflags="-X main.Version=$(git describe --always)" main.go hello
5e3fd7a
[hello]Nhìn chung sử dụng không khác biệt quá lớn so với go build, nên sẽ không trình bày quá nhiều.
tool
Bản thân lệnh tool không có chức năng nào, tác dụng của nó là gọi trực tiếp các công cụ trong thư mục cmd/, ví dụ cmd/compile là trình biên dịch đi kèm. Thông qua go tool có thể gọi trực tiếp các công cụ này, không cần phải thực thi các tệp nhị phân của những công cụ này thủ công.
$ go tool -h
usage: go tool [-n] command [args...]Sử dụng tham số -n để in ra tất cả các tham số lệnh được hỗ trợ
$ go tool -n
addr2line
asm
buildid
cgo
compile
covdata
cover
doc
fix
link
nm
objdump
pack
pprof
test2json
trace
vetNhững công cụ này được lưu trữ trong thư mục GOROOT/pkg/tool, và được phân nhóm theo hệ điều hành và kiến trúc CPU, như dưới đây.
$ ls $GOROOT/pkg/tool/windows_amd64/ -1
addr2line.exe*
asm.exe*
buildid.exe*
cgo.exe*
compile.exe*
covdata.exe*
cover.exe*
doc.exe*
fix.exe*
link.exe*
nm.exe*
objdump.exe*
pack.exe*
pprof.exe*
test2json.exe*
trace.exe*
vet.exe*Sử dụng định dạng go doc cmd/command để xem cách sử dụng của mỗi lệnh, ví dụ
$ go doc cmd/compile
Usage:
go tool compile [flags] file...
The specified files must be Go source files and all part of the same package.
The same compiler is used for all target operating systems and architectures.
The GOOS and GOARCH environment variables set the desired target.
Flags:
-D path
Set relative path for local imports.
-I dir1 -I dir2
Search for imported packages in dir1, dir2, etc,
after consulting $GOROOT/pkg/$GOOS_$GOARCH.
-L
Show complete file path in error messages.
...Các cờ tham số được hỗ trợ bởi cmd/compile, cũng chính là các tham số được hỗ trợ bởi gcflags đã đề cập trước đó. Sự khác biệt giữa go tool compile và go build là, cái trước chỉ phụ trách biên dịch, và chỉ có thể dùng tệp làm tham số, cái sau có thể dùng thư mục, gói, tệp làm tham số, và không chỉ làm mỗi việc biên dịch mã nguồn, còn phụ trách link các tệp, xóa các tệp vô dụng, v.v., cái trước là một phần của cái sau. Chúng ta có thể in ra các lệnh được thực thi trong quá trình build
$ go build -n main.go
#
# internal/goarch
#
mkdir -p $WORK\b004\
cat >$WORK\b004\importcfg << 'EOF' # internal
# import config
EOF
"/golang/pkg/tool/windows_amd64/compile.exe" -o "$WORK/b004/_pkg_.a" -trimpath "$WORK/b004=>" -p internal/goarch -std -+ -complete -buildid 3gunEkUExGdhOPa2rFsh/3gunEkUExGdhOPa2rFsh -goversion go1.21.0 -c=4 -nolocalimports -importcfg "$WORK/b004/importcfg" -pack "/golang/src/internal/goarch/goarch.go" "/golang/src/internal/goarch/goarch_amd64.go" "/golang/src/internal/goarch/zgoarch_amd64.go"
"/golang/pkg/tool/windows_amd64/buildid.exe" -w "$WORK/b004/_pkg_.a" # internal
...Trong quá trình có thể thấy có một đoạn /golang/pkg/tool/windows_amd64/compile.exe, chính là đã gọi trình biên dịch. Ngoài compile ra, còn rất nhiều công cụ có thể gọi, nhiều lệnh go thực chất là bí danh của chúng.
clean
Lệnh clean dùng để xóa các tệp đối tượng được tạo ra trong quá trình biên dịch
$ go clean -h
usage: go clean [clean flags] [build flags] [packages]
Run 'go help clean' for details.Nó hỗ trợ các cờ sau
-i: Xóa các tệp lưu trữ hoặc tệp nhị phân tương ứng-n: In ra các lệnh sẽ được thực thi trong quá trình xóa nhưng thực tế không thực thi-x: In ra các lệnh sẽ được thực thi trong quá trình xóa và thực thi chúng-r: Xóa đệ quy thông quaimport path-cache, xóa tất cả cache dogo buildtạo ra-testcache: Xóa tất cả cache kiểm thử được tạo ra-modcache: Xóa tất cả cache mô-đun đã tải xuống-fuzzcache: Xóa cache dofuzz testtạo ra.
Khi sử dụng go tool compile, là gọi trực tiếp lệnh trình biên dịch, không giống như go build sẽ làm nhiều xử lý hậu kỳ, sẽ tạo ra các tệp đối tượng. Ví dụ thực thi lệnh sau
go tool compile -N -S -l main.gosẽ tạo ra một tệp tên là main.o, sử dụng lệnh go clean để xóa là được. Hoặc sử dụng tham số -n để in ra các lệnh sẽ được thực thi.
$ go clean -n
rm -f golearn golearn.exe golearn golearn.exe golearn.test golearn.test.exe golearn.test golearn.test.exe api api.exe main main.exeXóa cache biên dịch, nó sẽ xóa các cache biên dịch được tạo ra trong thư mục GOCACHE
$ go clean -cache -n
rm -r /cache/00 /cache/01 /cache/02Xóa cache do fuzz test tạo ra, những cache này mặc định được lưu trữ trong thư mục GOCACHE/fuzz/
$ go clean -fuzzcache -n
rm -rf /cache/fuzzfix
Tính đến thời điểm viết bài này, go đã được mười năm, trong quá trình ngôn ngữ không ngừng cập nhật và sửa đổi, khó tránh khỏi xuất hiện một số vấn đề không tương thích do thay đổi API, lệnh fix được sinh ra vì mục đích này, nó sẽ phát hiện những API đã lỗi thời trong các tệp nguồn và thay thế chúng bằng các API mới.
$ go fix -h
usage: go fix [-fix list] [packages]
Run 'go help fix' for details.Nó hỗ trợ thư mục, tên tệp, đường dẫn làm tham số, nhận cờ -fix để truyền tham số nhằm biểu thị thực hiện sửa đổi nào, có thể xem các giá trị khả dụng thông qua lệnh got tool fix -help
$ go tool fix -help
usage: go tool fix [-diff] [-r fixname,...] [-force fixname,...] [path ...]
-diff
display diffs instead of rewriting files
-force string
force these fixes to run even if the code looks updated
-go string
go language version for files
-r string
restrict the rewrites to this comma-separated list
Available rewrites are:
buildtag
Remove +build comments from modules using Go 1.18 or later
cftype
Fixes initializers and casts of C.*Ref and JNI types
context
Change imports of golang.org/x/net/context to context
egl
Fixes initializers of EGLDisplay
eglconf
Fixes initializers of EGLConfig
gotypes
Change imports of golang.org/x/tools/go/{exact,types} to go/{constant,types}
jni
Fixes initializers of JNI's jobject and subtypes
netipv6zone
Adapt element key to IPAddr, UDPAddr or TCPAddr composite literals.
https://codereview.appspot.com/6849045/
printerconfig
Add element keys to Config composite literals.Dưới đây là một ví dụ, trong mã nguồn sử dụng gói golang.org/x/net/context
package main
import (
"fmt"
"golang.org/x/net/context"
)
func main() {
background := context.Background()
fmt.Println(background.Err())
}Sử dụng go fix để sửa, thay thế nó bằng gói context trong thư viện chuẩn, chúng ta có thể sử dụng lệnh sau để thay thế
$ go fix -fix context main.goCũng có thể không thay thế, xem sự thay đổi của tệp trước và sau.
$ go tool fix -r context -diff main.go
main.go: fixed context
diff main.go fixed/main.go
--- main.go
+++ fixed/main.go
@@ -1,8 +1,8 @@
package main
import (
+ "context"
"fmt"
- "golang.org/x/net/context"
)
func main() {Ngôn ngữ go đã ra đời hơn mười năm chỉ có chín tham số thay thế khả dụng, có thể thấy khả năng tương thích được giữ khá tốt.
fmt
Lệnh fmt là công cụ định dạng đi kèm của go, dùng để định dạng các tệp mã nguồn go.
$ go fmt -h
usage: go fmt [-n] [-x] [packages]
Run 'go help fmt' for details.Thông qua lệnh go doc gofmt để xem tài liệu chi tiết của nó
$ go doc cmd/gofmt
Gofmt formats Go programs. It uses tabs for indentation and blanks for
alignment. Alignment assumes that an editor is using a fixed-width font.
Usage:
gofmt [flags] [path ...]
The flags are:
-d
Do not print reformatted sources to standard output.
If a file's formatting is different than gofmt's, print diffs
to standard output.
-e
Print all (including spurious) errors.
-l
Do not print reformatted sources to standard output.
If a file's formatting is different from gofmt's, print its name
to standard output.
-r rule
Apply the rewrite rule to the source before reformatting.
-s
Try to simplify code (after applying the rewrite rule, if any).
-w
Do not print reformatted sources to standard output.
If a file's formatting is different from gofmt's, overwrite it
with gofmt's version. If an error occurred during overwriting,
the original file is restored from an automatic backup.gofmt sử dụng tab để thụt lề, khoảng trắng để căn chỉnh, trong trường hợp mặc định mã sau khi định dạng sẽ được xuất ra đầu ra chuẩn, không phải ghi đè lên tệp gốc. Lệnh go fmt thực tế sử dụng là lệnh gofmt, nó là một tệp nhị phân độc lập, nằm trong thư mục GOROOT/bin.
$ ls $GOROOT/bin -1
go.exe*
gofmt.exe*Thêm cờ -n cho lệnh go fmt là có thể biết các lệnh mà nó sẽ thực thi.
$ go fmt main.go
/golang/bin/gofmt.exe -l -w main.goCó thể thấy go fmt thực chất là bí danh của gofmt -l -w, lệnh gofmt có các tham số sau
-d: Xuất sự khác biệt của tệp trước và sau khi định dạng-e: Xuất tất cả lỗi-l: Xuất tên của các tệp có thay đổi-r: Áp dụng quy tắc định dạng-s: Thử đơn giản hóa mã-w: Ghi đè lên tệp nguồn, nếu xảy ra lỗi thì khôi phục bản sao lưu
Giả sử hiện có một tệp nguồn như sau
$ cat main.go
package main
import "fmt"
func main() {
fmt.Println("hello world!")}Thông qua tham số -d có thể xem trước sự thay đổi của nó
$ gofmt -d main.go
diff main.go.orig main.go
--- main.go.orig
+++ main.go
@@ -3,5 +3,5 @@
import "fmt"
func main() {
-fmt.Println("hello world!")}
-
+ fmt.Println("hello world!")
+}Tham số -l sẽ xuất tên của các tệp sẽ được sửa đổi
$ gofmt -l .
main.goNếu có lỗi cú pháp, tham số -e có thể xuất chi tiết hơn
$ gofmt -d -e main.go
main.go:6:27: missing ',' in argument list
main.go:6:28: expected operand, found newline
main.go:7:2: expected ')', found 'EOF'
main.go:7:2: expected ';', found 'EOF'
main.go:7:2: expected ';', found 'EOF'
main.go:7:2: expected '}', found 'EOF'
main.go:7:2: missing ',' in argument list-w sẽ áp dụng các sửa đổi vào tệp nguồn
$ gofmt -l -w .
main.go
$ cat main.go
package main
import "fmt"
func main() {
fmt.Println("hello world!")
}Bạn có thể phát hiện ra rằng với tư cách là một công cụ định dạng, gofmt hoàn toàn không cung cấp bất kỳ cấu hình tùy chỉnh nào, trong khi trình định dạng prettify chuyên làm đẹp mã js lại cung cấp khá nhiều cấu hình để định dạng mã, ở đây có thể thấy thái độ của官方 go, đừng nghĩ đến việc tùy chỉnh, tốt nhất là phong cách mã của tất cả mọi người nên nhất quán, ít nhất có một lợi ích là khi đọc mã không cần phải thích nghi với thói quen của người khác. Nhưng thực ra nó vẫn giữ lại một mục tùy chỉnh, đó là quy tắc thay thế mã định dạng, quy tắc có thể tùy chỉnh, định dạng như sau
pattern -> replacementVí dụ xóa các dấu ngoặc thừa
(a) -> aXem sự thay đổi của tệp
$ gofmt -r "(a) -> a" -d -l .
main.go
diff main.go.orig main.go
--- main.go.orig
+++ main.go
@@ -3,5 +3,5 @@
import "fmt"
func main() {
- fmt.Println(("hello world!"))
+ fmt.Println("hello world!")
}Có thể thấy gofmt sẽ xóa các dấu ngoặc thừa.
get
Lệnh get chắc chắn là lệnh được sử dụng nhiều nhất trong quá trình phát triển go, tác dụng của nó là tải xuống mã nguồn của gói có địa chỉ được chỉ định vào thư mục tương ứng của GOMODCACHE.
$ go get -h
usage: go get [-t] [-u] [-v] [build flags] [packages]
Run 'go help get' for details.-u: Thử cập nhật các phiên bản minor và patch của gói, nếu liên quan đến thay đổi phiên bản chính, ví dụv1->v2, sẽ không cập nhật.-t: Cập nhật các phiên bản phụ thuộc trong kiểm thử-v: Xuất các gói được biên dịch, thực tế thuộc về một trong các tham số củabuild flags
Trong thời kỳ cổ đại, tác dụng của go get tương tự như go install, nó sẽ tải xuống và biên dịch các gói này, tuy nhiên随着 sự ra đời và hoàn thiện của các mô-đun go, phần tác dụng này dần bị loại bỏ, lệnh get hiện được sử dụng phổ biến nhất là tải xuống và phân tích cú pháp các phụ thuộc cho các mô-đun go, nên bạn có thể thấy lệnh go get còn hỗ trợ các cờ build, và nếu bạn thử sử dụng go get bên ngoài một mô-đun giống như sử dụng go install, nó sẽ提示 bạn cách sử dụng này đã bị loại bỏ.
$ go get github.com/wire/wire
go: go.mod file not found in current directory or any parent directory.
'go get' is no longer supported outside a module.
To build and install a command, use 'go install' with a version,
like 'go install example.com/cmd@latest'
For more information, see https://golang.org/doc/go-get-install-deprecation
or run 'go help get' or 'go help install'.至于 tại sao trong mô tả tài liệu vẫn giữ lại những điều này thì cũng không biết, lật xem mã nguồn của lệnh get, bạn còn sẽ phát hiện nó vẫn giữ các flag trước đó.
var (
getD = CmdGet.Flag.Bool("d", true, "")
getF = CmdGet.Flag.Bool("f", false, "")
getFix = CmdGet.Flag.Bool("fix", false, "")
getM = CmdGet.Flag.Bool("m", false, "")
getT = CmdGet.Flag.Bool("t", false, "")
getU upgradeFlag
getInsecure = CmdGet.Flag.Bool("insecure", false, "")
// -v is cfg.BuildV
)Trở lại vấn đề chính, lệnh get sẽ tải xuống mã nguồn của gói được chỉ định vào thư mục phụ thuộc toàn cục local, tức là thư mục tương ứng của GOCACHE, sau đó ghi thông tin vào các tệp go.mod và go.sum, cái trước phụ trách ghi lại phiên bản, cái sau phụ trách ghi lại checksum sha1 để đảm bảo an toàn. Lệnh get thực tế dựa trên VCS, tức là hệ thống kiểm soát phiên bản local, tổng cộng hỗ trợ các loại sau
- git
- hg (Mercurial)
- bzr (Bazaar)
- svn
- fossil
Trong đó, mặc định chỉ hỗ trợ git và hg, có thể cấu hình trong GOVCS, định dạng như sau
GOVCS=github.com:git,example.com:hg,*:git|hg,*:allGOVCS chỉ hỗ trợ git và hg làm VCS, ba cái còn lại cần cấu hình trong GOPRIVATE.
Lệnh go get tổng cộng có các cách sử dụng sau, có thể trực tiếp dùng địa chỉ phụ thuộc làm tham số
$ go get golang.org/x/netCũng có thể chỉ định phiên bản
$ go get golang.org/x/net@0.17.0Chỉ định phiên bản mới nhất
$ go get golang.org/x/net@latestThử cập nhật phiên bản
$ go get -u golang.org/x/netXóa một phụ thuộc nào đó
$ go get golang.org/x/net@noneNhững điều trên là dùng để quản lý các phụ thuộc thông thường, nó còn có thể dùng để quản lý các phụ thuộc không mấy thông thường, ví dụ cập nhật phiên bản của go
$ go get go@latest
go: updating go.mod requires go >= 1.21.3; switching to go1.21.3
go: downloading go1.21.3 (windows/amd64)
go: upgraded go 1.21.0 => 1.21.3Thậm chí còn có thể dùng để cập nhật phiên bản của công cụ go
$ go get toolchain@latestKhi bạn sử dụng go get để cập nhật phiên bản go và công cụ, chúng sẽ cài đặt phiên bản go mới trong thư mục GOMODCACHE/golang.org/
$ ls $(go env GOMODCACHE)/golang.org -1
'toolchain@v0.0.1-go1.21.3.windows-amd64'/
x/Lúc này chỉ cần sửa đổi thủ công GOROOT là có thể chuyển sang phiên bản được chỉ định.
install
Lệnh install tương tự như lệnh get, chúng đều dùng để tải xuống các phụ thuộc bên thứ ba, nhưng khác biệt là lệnh get tải xuống mã nguồn, còn lệnh install sẽ biên dịch mã nguồn thành các tệp nhị phân có thể thực thi được trên máy này, đường dẫn lưu trữ của các tệp nhị phân trước hết là trong thư mục GOBIN, sau đó là GOPATH/bin. Chức năng chính của lệnh này là dùng để tải xuống một số công cụ dòng lệnh công khai của bên thứ ba, nhờ vào tốc độ biên dịch và khả năng di động của go, không cần tải xuống các tệp nhị phân, mà là tải xuống mã nguồn rồi biên dịch trên local.
$ go install -h
usage: go install [build flags] [packages]
Run 'go help install' for details.Lệnh install nhận các cờ build và tên gói làm tham số, trong trường hợp bật gomod, tên gói phải mang theo số phiên bản. Ví dụ tải xuống trình gỡ lỗi delve
$ go install -x github.com/go-delve/delve/cmd/dlv@latest
# get https://goproxy.cn/github.com/@v/list
# get https://goproxy.cn/github.com/go-delve/delve/cmd/@v/list
# get https://goproxy.cn/github.com/go-delve/delve/cmd/dlv/@v/list
# get https://goproxy.cn/github.com/go-delve/delve/@v/list
# get https://goproxy.cn/github.com/go-delve/@v/list
# get https://goproxy.cn/github.com/@v/list: 404 Not Found (0.014s)
# get https://goproxy.cn/github.com/go-delve/delve/cmd/@v/list: 404 Not Found (0.027s)
# get https://goproxy.cn/github.com/go-delve/delve/cmd/dlv/@v/list: 404 Not Found (0.027s)
# get https://goproxy.cn/github.com/go-delve/delve/@v/list: 200 OK (0.027s)
# get https://goproxy.cn/github.com/go-delve/@v/list: 404 Not Found (0.027s)
WORK=/home/user/tmp/go-build2033992495
mkdir -p $WORK/b001/
cat >/home/user/tmp/go-build2033992495/b001/importcfg.link << 'EOF' # internal
packagefile github.com/go-delve/delve/cmd/dlv=/home/user/.cache/go-build/f1/f11d552287458c0fce625abe50bf928c487064c36bbb1251ad8b1968772c3e4b-d
......
......
mkdir -p /home/wyh/gomod/bin/
mv $WORK/b001/exe/a.out /home/wyh/gomod/bin/dlv
rm -r $WORK/b001/Nó trước hết sẽ tải xuống mã nguồn vào đường dẫn được lưu trữ của GOMODCACHE, điểm này giống với lệnh get, sau đó chuyển sang thư mục làm việc tạm thời, biên dịch nó, sau khi biên dịch xong sẽ di chuyển tệp nhị phân vào thư mục GOPATH/bin, cuối cùng xóa thư mục tạm thời. Lệnh install còn có một hạn chế là gói được tải xuống phải là gói entry của dự án đó, tức là phải chứa tệp entry main.go, nếu không sẽ提示 bạn không thể cài đặt. Ví dụ, sử dụng go install để tải xuống gin
$ go install -x github.com/gin-gonic/gin@latest
# get https://goproxy.cn/github.com/@v/list
# get https://goproxy.cn/github.com/gin-gonic/gin/@v/list
# get https://goproxy.cn/github.com/gin-gonic/@v/list
# get https://goproxy.cn/github.com/@v/list: 404 Not Found (0.022s)
# get https://goproxy.cn/github.com/gin-gonic/gin/@v/list: 200 OK (0.027s)
# get https://goproxy.cn/github.com/gin-gonic/@v/list: 404 Not Found (0.028s)
package github.com/gin-gonic/gin is not a main packagegin là một thư viện phụ thuộc của web framework, không phải là một công cụ dòng lệnh, đương nhiên cũng không có tệp entry, nên cũng sẽ cài đặt thất bại.
list
Lệnh list sẽ liệt kê các gói ở vị trí được chỉ định, mỗi dòng một, và hỗ trợ xuất định dạng tùy chỉnh, hỗ trợ rất nhiều tham số, điều kiện tiên quyết để sử dụng nó là phải trong một dự án hỗ trợ gomod.
$ go list -h
usage: go list [-f format] [-json] [-m] [list flags] [build flags] [packages]
Run 'go help list' for details.Các tham số nó hỗ trợ như sau
-f: Tham số định dạng-json: Xuất định dạng json-compiled: Hiển thị tất cả các gói sẽ được trình biên dịch biên dịch-deps: Hiển thị tên của mỗi gói và từng phụ thuộc của nó-test: Hiển thị gói kiểm thử của mỗi gói-e: Xuất bình thường khi gặp các gói có lỗi-find: Không phân tích cú pháp các quan hệ phụ thuộc của các gói này-export: Khi sử dụng tham số này, thiết lập giá trị của trườngPackage.Exportcủa cấu trúc là tệp chứa thông tin export mới nhất của gói được chỉ định, và thiết lập giá trị của trườngPackage.BuildIDlàBuildIDcủa gói, chủ yếu dùng cho xuất định dạng.
Tham số thông tin mô-đun,
-m: Xuất mô-đun thay vì xuất gói-versions: Hiển thị tất cả thông tin khả dụng của một mô-đun-retracted: Hiển thị các phiên bản bị rút lại của một mô-đun
Tham số [packages] có thể là một tên gói được chỉ định, hoặc một thư mục, cũng có thể là all, biểu thị bất kỳ đâu, khi sử dụng tham số -m, all biểu thị tất cả các phụ thuộc được引用 bởi mô-đun hiện tại.
Ví dụ, tệp hiện tại chỉ có một tệp main.go, và chỉ có một dòng mã xuất "hello world", sau khi thực thi go list -deps ., nó xuất tất cả các gói được引用 từ dự án hiện tại đến fmt và các phụ thuộc của nó.
$ ls
go.mod go.sum main.go
$ cat main.go
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
$ go list -deps .
internal/goarch
unsafe
internal/abi
internal/unsafeheader
internal/cpu
internal/bytealg
internal/coverage/rtcov
internal/godebugs
internal/goexperiment
internal/goos
runtime/internal/atomic
runtime/internal/math
runtime/internal/sys
runtime
......
......
path
io/fs
os
fmt
golearnHoặc xuất tất cả các phụ thuộc mô-đun trong dự án hiện tại
$ go list -m all
golearn
cloud.google.com/go v0.26.0
github.com/246859/containers v0.0.1
github.com/246859/river v0.1.0 => D:\WorkSpace\Code\riverdb
github.com/BurntSushi/toml v0.3.1
github.com/Jleagle/steam-go v0.0.0-20230725082712-1053b441b1f2
github.com/Jleagle/unmarshal-go v0.0.0-20210227002040-694f544f9265
github.com/KyleBanks/depth v1.2.1
github.com/Microsoft/go-winio v0.6.1
github.com/PuerkitoBio/purell v1.1.1
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578
github.com/andeya/ameda v1.5.3
github.com/andeya/goutil v1.0.1
...format
Đầu ra của lệnh list là theo dòng, mỗi dòng xuất ra đều là một gói.官方 cung cấp tham số -f để chúng ta tùy chỉnh định dạng xuất dòng, giá trị mà nó nhận cũng chính là cú pháp mẫu được định nghĩa bởi gói công cụ mẫu template/text, ví dụ như ví dụ dưới đây
-f "package {{ .Dir }} {{ .Name }}"Mỗi gói được lặp sẽ được truyền vào dưới dạng cấu trúc sau, tất cả các trường trong cấu trúc này đều có thể được sử dụng làm tham số mẫu.
type Package struct {
Dir string // directory containing package sources
ImportPath string // import path of package in dir
ImportComment string // path in import comment on package statement
Name string // package name
Doc string // package documentation string
Target string // install path
Shlib string // the shared library that contains this package (only set when -linkshared)
Goroot bool // is this package in the Go root?
Standard bool // is this package part of the standard Go library?
Stale bool // would 'go install' do anything for this package?
StaleReason string // explanation for Stale==true
Root string // Go root or Go path dir containing this package
ConflictDir string // this directory shadows Dir in $GOPATH
BinaryOnly bool // binary-only package (no longer supported)
ForTest string // package is only for use in named test
Export string // file containing export data (when using -export)
BuildID string // build ID of the compiled package (when using -export)
Module *Module // info about package's containing module, if any (can be nil)
Match []string // command-line patterns matching this package
DepOnly bool // package is only a dependency, not explicitly listed
DefaultGODEBUG string // default GODEBUG setting, for main packages
// Source files
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
CgoFiles []string // .go source files that import "C"
CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
IgnoredGoFiles []string // .go source files ignored due to build constraints
IgnoredOtherFiles []string // non-.go source files ignored due to build constraints
CFiles []string // .c source files
CXXFiles []string // .cc, .cxx and .cpp source files
MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
FFiles []string // .f, .F, .for and .f90 Fortran source files
SFiles []string // .s source files
SwigFiles []string // .swig files
SwigCXXFiles []string // .swigcxx files
SysoFiles []string // .syso object files to add to archive
TestGoFiles []string // _test.go files in package
XTestGoFiles []string // _test.go files outside package
// Embedded files
EmbedPatterns []string // //go:embed patterns
EmbedFiles []string // files matched by EmbedPatterns
TestEmbedPatterns []string // //go:embed patterns in TestGoFiles
TestEmbedFiles []string // files matched by TestEmbedPatterns
XTestEmbedPatterns []string // //go:embed patterns in XTestGoFiles
XTestEmbedFiles []string // files matched by XTestEmbedPatterns
// Cgo directives
CgoCFLAGS []string // cgo: flags for C compiler
CgoCPPFLAGS []string // cgo: flags for C preprocessor
CgoCXXFLAGS []string // cgo: flags for C++ compiler
CgoFFLAGS []string // cgo: flags for Fortran compiler
CgoLDFLAGS []string // cgo: flags for linker
CgoPkgConfig []string // cgo: pkg-config names
// Dependency information
Imports []string // import paths used by this package
ImportMap map[string]string // map from source import to ImportPath (identity entries omitted)
Deps []string // all (recursively) imported dependencies
TestImports []string // imports from TestGoFiles
XTestImports []string // imports from XTestGoFiles
// Error information
Incomplete bool // this package or a dependency has an error
Error *PackageError // error loading package
DepsErrors []*PackageError // errors loading dependencies
}
type PackageError struct {
ImportStack []string // shortest path from package named on command line to this one
Pos string // position of error (if present, file:line:col)
Err string // the error itself
}Nếu lặp là mô-đun, thì sẽ được truyền vào dưới dạng cấu trúc sau, tất cả các trường của nó cũng có thể được sử dụng làm tham số mẫu.
type Module struct {
Path string // module path
Query string // version query corresponding to this version
Version string // module version
Versions []string // available module versions
Replace *Module // replaced by this module
Time *time.Time // time version was created
Update *Module // available update (with -u)
Main bool // is this the main module?
Indirect bool // module is only indirectly needed by main module
Dir string // directory holding local copy of files, if any
GoMod string // path to go.mod file describing module, if any
GoVersion string // go version used in module
Retracted []string // retraction information, if any (with -retracted or -u)
Deprecated string // deprecation message, if any (with -u)
Error *ModuleError // error loading module
Origin any // provenance of module
Reuse bool // reuse of old module info is safe
}
type ModuleError struct {
Err string // the error itself
}Xem tất cả các gói
$ go list -f "package {{.Dir}} {{.Name}}" ./...
package /golearn main
package /golearn/app cmd
package /golearn/cmd cmd
package /golearn/docs docs
package /golearn/tool tool
package /golearn/tool_test toolXem mô-đun
$ go list -m -f "mod {{.Path}} {{.Version}} {{.GoVersion}} {{.GoMod}}"
mod golearn 1.21.3 /golearn/go.modmod
go mod là lệnh chuyên dùng để quản lý các mô-đun go.
$ go mod help
Go mod provides access to operations on modules.
Note that support for modules is built into all the go commands,
not just 'go mod'. For example, day-to-day adding, removing, upgrading,
and downgrading of dependencies should be done using 'go get'.
See 'go help modules' for an overview of module functionality.
Usage:
go mod <command> [arguments]
The commands are:
download download modules to local cache
edit edit go.mod from tools or scripts
graph print module requirement graph
init initialize new module in current directory
tidy add missing and remove unused modules
vendor make vendored copy of dependencies
verify verify dependencies have expected content
why explain why packages or modules are needed
Use "go help mod <command>" for more information about a command.Nó có các lệnh con sau
download: Tải xuống tất cả các phụ thuộc được chỉ định trong tệpgo.modvào cache localedit: Chỉnh sửa tệpgo.mod, giao diện dòng lệnh mà nó cung cấp chủ yếu dùng để các công cụ hoặc script khác gọi.init: Khởi tạo một dự án gomod trong thư mục hiện tạitidy: Tải xuống các phụ thuộc bị thiếu, xóa các phụ thuộc không dùnggraph: Xuất biểu đồ phụ thuộcverify: Xác minh các phụ thuộc localwhy: Giải thích tại sao lại phụ thuộc vào các mô-đun nàyvendor: Export các phụ thuộc của dự án vào thư mục vendor
init
$ go help mod init
usage: go mod init [module-path]Lệnh init dùng để khởi tạo một dự án gomod, tham số duy nhất của nó là đường dẫn mô-đun, sau này nếu người khác muốn tải xuống phụ thuộc của bạn sẽ cần dựa vào đường dẫn mô-đun này làm cơ sở. Quy tắc đặt tên của nó thường là
domain_name/user_name/repo_nameVí dụ thường thì mọi người đều đặt dự án trên github, nên có thể là
github.com/jack/gotourKhông khuyến nghị sử dụng một số ký tự đặc biệt làm đường dẫn mô-đun. Dưới đây xem một trường hợp sử dụng
$ mkdir gotour
$ cd gotour
$ go mod init "github.com/jack/gotour"
go: creating new go.mod: module github.com/jack/gotourtidy
$ go help mod tidy
usage: go mod tidy [-e] [-v] [-x] [-go=version] [-compat=version]Lệnh tidy sẽ xóa các mục phụ thuộc không dùng trong go.mod, tức là các mục phụ thuộc không được引用, và sẽ tải xuống những mục phụ thuộc được引用 nhưng không tồn tại. Nó hỗ trợ các tham số sau
-v, xuất những phụ thuộc mô-đun bị xóa-e, nếu trong quá trình xảy ra lỗi thì bỏ qua nó và tiếp tục thực thi-x, xuất quá trình thực thi-go=version, cập nhật phiên bản go trong tệpgo.mod-compact=version, giữ lại bất kỳ checksum bổ sung nào cần thiết từ các phiên bản Go chính được chỉ định để tải thành công biểu đồ mô-đun, và nếu lệnhgocủa phiên bản đó tải bất kỳ gói được import nào từ các phiên bản mô-đun khác nhau, sẽ khiến tidy báo lỗi. Tham số này thường hiếm khi được sử dụng, nói chung chỉ xảy ra lỗi khi thay đổi phiên bản, có thể đến stackoverflow xem câu trả lời này go modules - go mod tidy error message: "but go 1.16 would select" - Stack Overflow
Xem một ví dụ sử dụng
$ go mod tidy -v
unused github.com/246859/containers
unused github.com/246859/river
unused github.com/Jleagle/steam-go
unused github.com/Jleagle/unmarshal-go
unused github.com/KyleBanks/depth
unused github.com/Microsoft/go-winio
unused github.com/PuerkitoBio/purell
unused github.com/PuerkitoBio/urlesc
unused github.com/andeya/ameda
unused github.com/andeya/goutil
unused github.com/asaskevich/govalidator
unused github.com/buger/jsonparser
unused github.com/bwmarrin/snowflake
unused github.com/bytedance/go-tagexpr/v2
unused github.com/bytedance/sonic
unused github.com/cespare/xxhash/v2
unused github.com/chenzhuoyu/base64x
......download
$ go help mod download
usage: go mod download [-x] [-json] [-reuse=old.json] [modules]Mặc dù tên của lệnh download dịch ra là tải xuống, nhưng nó chỉ tải các phụ thuộc vào cache phụ thuộc local, sẽ không sửa đổi tệp go.mod, tác dụng của nó là tải trước các phụ thuộc vào cache tệp local, nếu bạn muốn tải xuống một phụ thuộc nào đó, khuyến nghị sử dụng go get hoặc go mod tidy.
Dưới đây là một vài ví dụ sử dụng
$ go mod download -x gorm.io/gorm
# get https://goproxy.cn/gorm.io/gorm/@v/list
# get https://goproxy.cn/gorm.io/gorm/@v/list: 200 OK (0.084s)Nếu không có tham số nào, nó sẽ tải xuống tất cả các phụ thuộc tồn tại trong tệp go.mod nhưng không tồn tại trong cache phụ thuộc local, nếu không có gì cần tải xuống nó sẽ xuất
go: no module dependencies to downloadedit
$ go help mod edit
usage: go mod edit [editing flags] [-fmt|-print|-json] [go.mod]edit là một giao diện dòng lệnh, dùng để sửa đổi tệp go.mod, thường là để các chương trình khác sử dụng, một số IDE của trình soạn thảo để cung cấp hỗ trợ gomod sẽ sử dụng các lệnh này. Nó hỗ trợ các tham số sau
-module, sửa đổi đường dẫn mô-đun-go=version, sửa đổi phiên bản go mong đợi-require=path@version, thêm một mục phụ thuộc-droprequire=path@version, xóa một mục phụ thuộc-exclude=path@version, thêm một mục loại trừ phụ thuộc-dropexclude=path@version, xóa một mục loại trừ phụ thuộc-replace=old@version=new@version, thêm một mục thay thế phụ thuộc-dropreplace=old@version, xóa một mục thay thế phụ thuộc-retract=version, thêm một mục lùi phiên bản-dropretract=version, xóa một mục lùi phiên bản
Còn có một số tham số khác dùng để hiển thị
-print, xuất nội dung tệp-json, xuất dưới dạng json
Ví dụ như ví dụ dưới đây
$ go mod edit -print
module golearn
go 1.21.3
require (
github.com/dstgo/task v1.2.0
github.com/spf13/cast v1.5.1
github.com/swaggo/swag v1.16.2
golang.org/x/net v0.19.0
gorm.io/gorm v1.25.5
)graph
$ go help mod graph
usage: go mod graph [-go=version] [-x]Lệnh graph sẽ xuất biểu đồ phụ thuộc trong dự án hiện tại, khả năng đọc của nó rất kém, và hầu hết thời gian không phải để con người đọc, kết quả của nó thường được xử lý rồi hiển thị dưới dạng trực quan. Mỗi dòng là một phụ thuộc, định dạng như sau
引用方 被引用方Ví dụ
golearn go@1.21.3Nó còn hỗ trợ hai tham số
-go=version, sử dụng phiên bản go đã cho để tải biểu đồ phụ thuộc, giá trị của nó không thể nhỏ hơn phiên bản trong tệpgo.mod.-x, hiển thị các lệnh được thực thi trong quá trình.
Xem một ví dụ sử dụng đơn giản
$ go mod graph
golearn github.com/246859/containers@v0.0.1
golearn github.com/246859/river@v0.1.0
golearn github.com/Jleagle/steam-go@v0.0.0-20230725082712-1053b441b1f2
golearn github.com/Jleagle/unmarshal-go@v0.0.0-20210227002040-694f544f9265
golearn github.com/KyleBanks/depth@v1.2.1
golearn github.com/Microsoft/go-winio@v0.6.1
golearn github.com/PuerkitoBio/purell@v1.1.1
golearn github.com/PuerkitoBio/urlesc@v0.0.0-20170810143723-de5bf2ad4578
golearn github.com/andeya/ameda@v1.5.3
golearn github.com/andeya/goutil@v1.0.1
golearn github.com/asaskevich/govalidator@v0.0.0-20230301143203-a9d515a09cc2
golearn github.com/buger/jsonparser@v1.1.1
golearn github.com/bwmarrin/snowflake@v0.3.0
golearn github.com/bytedance/go-tagexpr/v2@v2.9.11
......vendor
$ go help mod vendor
usage: go mod vendor [-e] [-v] [-o outdir]vendor là một giải pháp thay thế cho gopath trước khi gomod chưa được giới thiệu, mỗi dự án go đều có một thư mục vendor, lưu trữ từng phụ thuộc của mỗi dự án riêng biệt theo định dạng domain/user/project, giống như node_module cồng kềnh của nodeJs bên cạnh, từng phụ thuộc của mỗi dự án được đặt riêng, cách quản lý phụ thuộc này hiện nay trông thực sự rất ngốc, nhưng vào thời điểm đó thực sự không có giải pháp nào tốt hơn, lý do giữ lại vendor là vì go tuân thủ cam kết tương thích ngược, một số dự án cũ bao gồm cả mã nguồn go có thể vẫn đang sử dụng vendor.
Trở lại vấn đề chính, vendor là một lệnh con của go mod, nó có thể export các phụ thuộc toàn cục được引用 bởi mô-đun hiện tại vào thư mục vendor.
$ go mod vendor -h
usage: go mod vendor [-e] [-v] [-o outdir]
Run 'go help mod vendor' for details.Nó có các tham số sau
-o: Chỉ định đường dẫn thư mục xuất-v: Xuất từng phụ thuộc-e: Không thoát khi xảy ra lỗi vẫn tiếp tục
Dưới đây xem một ví dụ, trước hết dùng go list -m all để xem các phụ thuộc được引用 bởi dự án hiện tại
$ go list -m all
github.com/dstgo/task
github.com/davecgh/go-spew v1.1.1
github.com/pkg/errors v0.9.1
github.com/pmezard/go-difflib v1.0.0
github.com/stretchr/objx v0.5.0
github.com/stretchr/testify v1.8.4
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
gopkg.in/yaml.v3 v3.0.1Export vào thư mục vendor hiện tại
$ go mod vendor -v -e -o vendor
# github.com/davecgh/go-spew v1.1.1
## explicit
github.com/davecgh/go-spew/spew
# github.com/pkg/errors v0.9.1
## explicit
github.com/pkg/errors
# github.com/pmezard/go-difflib v1.0.0
## explicit
github.com/pmezard/go-difflib/difflib
# github.com/stretchr/testify v1.8.4
## explicit; go 1.20
github.com/stretchr/testify/assert
# gopkg.in/yaml.v3 v3.0.1
## explicit
gopkg.in/yaml.v3Cấu trúc thư mục sau khi export như sau
└─vendor
├─github.com
│ ├─davecgh
│ │ └─go-spew
│ │ └─spew
│ ├─pkg
│ │ └─errors
│ ├─pmezard
│ │ └─go-difflib
│ │ └─difflib
│ └─stretchr
│ └─testify
│ └─assert
└─gopkg.in
| └─yaml.v3
|
|--modules.txtTrong đó modules.txt là tệp mô tả tất cả các mục phụ thuộc, cũng giống như go.mod hiện nay.
verify
$ go help mod verify
usage: go mod verifyLệnh này sẽ kiểm tra xem các phụ thuộc của dự án có bị sửa đổi sau khi tải xuống local hay không. Ví dụ, nếu không có vấn đề gì sẽ xuất all modules verified
$ go mod verify
all modules verifiedNếu không nó sẽ báo cáo nơi đã xảy ra thay đổi, và kết thúc lệnh với trạng thái không bình thường. Ví dụ
$ go mod verify
gorm.io/gorm v1.25.5: dir has been modified (/go/mod/libs/gorm.io/gorm@v1.25.5)why
$ go help mod why
usage: go mod why [-m] [-vendor] packages...Giải thích tại sao gói này lại được phụ thuộc, thực tế là xuất biểu đồ phụ thuộc liên quan đến nó. Ví dụ
$ go mod why gorm.io/gorm
# gorm.io/gorm
golearn
gorm.io/gormMặc định chỉ phân tích cú pháp các import từ main, thêm tham số -m có thể phân tích tình hình import của từng gói.
work
Lệnh work là một công cụ phát triển local dùng để quản lý nhiều mô-đun go
$ go work help
Work provides access to operations on workspaces.
Note that support for workspaces is built into many other commands, not
just 'go work'.
The commands are:
edit edit go.work from tools or scripts
init initialize workspace file
sync sync workspace build list to modules
use add modules to workspace file
vendor make vendored copy of dependencies
Use "go help work <command>" for more information about a command.init
Lệnh con init dùng để khởi tạo một workspace, lệnh này sẽ tạo một tệp tên là go.work
$ go work init -h
usage: go work init [moddirs]
Run 'go help work init' for details.Nhận tham số [moddirs] để chỉ định đưa những mô-đun nào vào quản lý, ví dụ
$ go work init ./service ./apiuse
Lệnh con use dùng để thêm các thư mục mô-đun được quản lý vào go.work
$ go help work use
usage: go work use [-r] [moddirs]
Use provides a command-line interface for adding
directories, optionally recursively, to a go.work file.Nhận [moddirs] làm tham số, còn có một -r biểu thị tìm kiếm đệ quy các mô-đun trong đường dẫn [moddirs], ví dụ
$ go work use -r ./oss-api ./multi_modulesedit
Tác dụng của lệnh con edit giống với go mod edit, đều là để lại giao diện dòng lệnh cho các công cụ và script khác thao tác.
$ go help work edit
usage: go work edit [editing flags] [go.work]
Edit provides a command-line interface for editing go.work,
for use primarily by tools or scripts. It only reads go.work;
it does not look up information about the modules involved.
If no file is specified, Edit looks for a go.work file in the current
directory and its parent directoriesCác tham số như sau
-fmt, định dạng tệpgo.work-use,-dropuse, thêm và xóa đường dẫn mô-đun-replace=old[@v]=new[@v],-dropreplace=old[@v]=new[@v], dùng để thêm và xóa các mô-đun cần thay thế-go,-toolchain=name, chỉ định phiên bản go, và chỉ định công cụ cần sử dụng-print, in ra các sửa đổi cuối cùng, không ghi lại vào tệp-json, xuất dưới dạngjson, không thể tồn tại cùng với-print, tương ứng với cấu trúc loại như saugotype GoWork struct { Go string Toolchain string Use []Use Replace []Replace } type Use struct { DiskPath string ModulePath string } type Replace struct { Old Module New Module } type Module struct { Path string Version string }
Một số ví dụ sử dụng như sau, xuất định dạng
$ go work edit -fmt -print
go 1.22.0
use (
./ab/cd
./auth
./user
)Xuất json
$ go work edit -fmt -json
{
"Go": "1.22.0",
"Use": [
{
"DiskPath": "./ab/cd"
},
{
"DiskPath": "./auth"
},
{
"DiskPath": "./user"
}
],
"Replace": null
}sync
Lệnh con sync dùng để đồng bộ danh sách các mô-đun trong go.work về các mô-đun trong workspace.
$ go help work sync
usage: go work sync
Sync syncs the workspace's build list back to the
workspace's modulesQuá trình này chủ yếu xảy ra sau khi phát triển local hoàn thành, các mô-đun đã hoàn thành công việc phát hành, lúc này sử dụng sync, nó sẽ cập nhật các phụ thuộc trong go.mod của tất cả các mô-đun trong worksapce dựa trên các quan hệ phụ thuộc của từng mô-đun, từ đó không cần chúng ta cập nhật thủ công.
vendor
Lệnh vendor sẽ sao chép tất cả các thư viện phụ thuộc của tất cả các mô-đun trong workspace vào thư mục vendor.
$ go work help vendor
usage: go work vendor [-e] [-v] [-o outdir]Chức năng giống với go mod vendor, sẽ không trình bày quá nhiều.
vet
Lệnh vet là một công cụ kiểm tra lỗi tĩnh cho mã nguồn go, giống như các công cụ lint của các ngôn ngữ khác, ví dụ Eslint.
$ go vet -h
usage: go vet [build flags] [-vettool prog] [vet flags] [packages]
Run 'go help vet' for details.
Run 'go tool vet help' for a full list of flags and analyzers.
Run 'go tool vet -help' for an overview.Trước hết xem một ví dụ đơn giản, hiện có mã nguồn như sau
$ cat main.go
package main
import "fmt"
func main(){
fmt.Println("hello world!"
}Thực thi go vet không có tham số nào trong cùng cấp thư mục
$ go vet
vet: ./main.go:6:28: missing ',' before newline in argument list (and 1 more errors)vet sẽ báo cáo tệp nào dòng nào xảy ra vấn đề gì. Nó hỗ trợ các cờ build làm tham số, ví dụ -n và -x, hỗ trợ gói, thư mục, tên tệp làm tham số.
$ go vet .
$ go vet main.go
$ go vet ./cmd
$ go vet runtimeThông qua lệnh sau để xem các tham số và giải thích chi tiết hơn của nó.
$ go tool vet help
vet is a tool for static analysis of Go programs.
vet examines Go source code and reports suspicious constructs,
such as Printf calls whose arguments do not align with the format
string. It uses heuristics that do not guarantee all reports are
genuine problems, but it can find errors not caught by the compilers.
Registered analyzers:
asmdecl report mismatches between assembly files and Go declarations
assign check for useless assignments
atomic check for common mistakes using the sync/atomic package
bools check for common mistakes involving boolean operators
buildtag check //go:build and // +build directives
......Lệnh go tool vet không thể trực tiếp dùng để kiểm tra mã, nên sử dụng go vet. Tham số [vet flag] của go vet hỗ trợ thiết lập các bộ phân tích mã, các giá trị khả dụng như sau
asmdecl Kiểm tra xem các tệp hợp ngữ có khớp với các khai báo go không
assign Kiểm tra xem có các biến không dùng không
atomic Kiểm tra xem có phá vỡ tính nguyên tử khi sử dụng sync/atomic không
bools Kiểm tra xem có sử dụng sai các toán tử logic không
buildtag Kiểm tra các tag build
cgocall Kiểm tra các hành vi vi phạm quy tắc truyền con trỏ cgao
composites Kiểm tra các cấu trúc composite chưa khởi tạo, ví dụ map, chan
copylocks Kiểm tra xem có xảy ra sao chép giá trị của khóa không
directive Kiểm tra các lệnh của công cụ go
errorsas Kiểm tra xem có truyền các kiểu không phải con trỏ hoặc không phải kiểu error cho errors.As không
framepointer Kiểm tra xem mã hợp ngữ sau khi tối ưu hóa biên dịch có xóa frame pointer trước khi lưu nó không
httpresponse Kiểm tra xem có sử dụng sai httpresponse không
ifaceassert Kiểm tra các khẳng định kiểu từ interface sang interface
loopclosure Vấn đề tham chiếu của các biến vòng lặp
lostcancel context.WithCancel không sử dụng hàm cancel
nilfunc Kiểm tra xem có so sánh vô ích giữa các hàm và nil không
printf Kiểm tra xem các tham số định dạng của printf có đúng không
shift Kiểm tra xem có các phép dịch chuyển bằng hoặc vượt quá độ rộng số nguyên không
sigchanyzer Kiểm tra các chan os.Signal không có bộ đệm
slog Kiểm tra các cuộc gọi log có cấu trúc không hợp lệ
stdmethods Kiểm tra xem các chữ ký của các phương thức interface đã biết có đúng không
stringintconv Kiểm tra các chuyển đổi chuỗi-số nguyên
structtag Kiểm tra xem các tag của cấu trúc có đúng không
testinggoroutine Kiểm tra xem có sử dụng goroutine trong kiểm thử để gọi testing.Fatal không
tests Kiểm tra các lỗi sử dụng phổ biến trong kiểm thử và ví dụ
timeformat Kiểm tra xem định dạng thời gian của (time.Time).Format hoặc time.Parse có đúng không
unmarshal Kiểm tra xem có truyền các kiểu không phải con trỏ hoặc không phải interface cho unmarshal không
unreachable Kiểm tra các mã không thể đến được
unsafeptr Kiểm tra các chuyển đổi không đúng từ uintptr sang unsafe.Pointer
unusedresult Kiểm tra các giá trị trả về của hàm không được sử dụngChúng đều là các bộ phân tích phân tích cho một điểm cụ thể nào đó, ví dụ bộ phân tích timeformat kiểm tra xem cuộc gọi của time.Format có tuân thủ cú pháp đúng không. Trong trường hợp mặc định tất cả các bộ phân tích trên đều được bật, nếu muốn bật riêng có thể sử dụng định dạng sau
$ go vet -timeformat main.goTắt riêng
$ go vet -timeformat=false main.goMã nguồn của các bộ phân tích này nằm trong cmd/vendor/golang.org/x/tools/go/analysis/passes, mỗi bộ phân tích đều là một lỗi dễ mắc phải trong go, nên rất khuyến nghị sử dụng lệnh vet để kiểm tra mã của bạn. Ngoài những điều này ra, nó còn hỗ trợ một số cờ tham số khác
-V, chỉ in phiên bản rồi thoát-json, xuất dưới dạng json-c=n, hiển thị số dòng xung đột được chỉ định trong ngữ cảnh (dường như không có tác dụng gì)
Còn có một số bộ phân tích bên ngoài, ví dụ shadows, nó phụ trách phát hiện các vấn đề ẩn của các biến được đặt tên ngắn, vì là bên ngoài nên cần dùng go install để tải xuống
$ go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latestĐịnh dạng sử dụng như sau
$ go vet -vettool=$(which shadow)test
$ go test -h
usage: go test [build/test flags] [packages] [build/test flags & test binary flags]
Run 'go help test' and 'go help testflag' for details.Lệnh test là lệnh cung cấp chức năng kiểm thử trong bộ công cụ go, chức năng này khá quan trọng, đối với một phần mềm而言, kiểm thử hoàn thiện là điều không thể thiếu. Ở đây chỉ đơn giản giới thiệu cách sử dụng lệnh test, nếu muốn tìm hiểu thêm về kiểm thử, truy cập: Kiểm thử
Nó ngoài hỗ trợ các tham số biên dịch của lệnh build ra, test còn hỗ trợ các tham số sau
-args, các tham số entry của chương trình-c, biên dịch các tệp kiểm thử nhị phân của gói hiện tại vào thư mục hiện tại nhưng không thực thi, đặt tên theo cáchpkg.test-exec, thực thi một số lệnh khác trước khi bắt đầu kiểm thử-json, phong cách xuất của kiểm thử变为 json-o, chỉ định đường dẫn của tệp nhị phân kiểm thử
Nó còn hỗ trợ nhiều testflag, sử dụng lệnh help để xem tất cả testflag
$ go help testflag
`go test` 命令既接受作用于 `go test` 本身的标志,
也接受作用于生成的测试二进制文件的标志。
`go test` 命令识别以下标志,并用于控制任何测试的执行:
-bench regexp
-benchtime t
-count n
......Giới thiệu một số常用
-v, xuất kết quả kiểm thử của từng trường hợp sử dụng.-timeout duration, thời gian超时 thực thi kiểm thử-skip regexp, bỏ qua các trường hợp kiểm thử được chỉ định-short, rút ngắn thời gian chạy của những trường hợp kiểm thử chạy rất lâu-shuffle, xáo trộn thứ tự thực thi của tất cả các trường hợp kiểm thử-run regexp, chạy các trường hợp kiểm thử được chỉ định-list regexp, liệt kê từng trường hợp kiểm thử-cpu 1,2,4, chỉ định số lượng cpu-count n, chỉ định mỗi trường hợp kiểm thử thực thi bao nhiêu lần
Cách sử dụng đơn giản nhất là, không có tham số nào, nó sẽ thực thi tất cả các trường hợp kiểm thử trong gói hiện tại, và xuất kết quả.
$ ls *_test.go
hello_test.go
$ go test
PASS
ok golearn 0.522sChỉ định một tệp kiểm thử nào đó
$ go test hello_test.go
ok command-line-arguments 0.041sThêm tham số -v có thể xem xuất chi tiết hơn, nó khá常用.
$ go test -v hello_test.go
=== RUN TestHello
hello_test.go:6: hello world!
--- PASS: TestHello (0.00s)
PASS
ok command-line-arguments 0.041sChỉ định một trường hợp kiểm thử nào đó
$ go test -v -run TestHello
=== RUN TestHello
hello_test.go:6: hello world!
--- PASS: TestHello (0.00s)
PASS
ok golearn 0.028sKhi kiểm thử, lệnh test có hai chế độ, trước hết nói về chế độ thư mục đầu tiên, khi thực thi lệnh test không có tham số package, nó sẽ thực thi kiểm thử theo chế độ thư mục, ví dụ như các lệnh dưới đây
$ go test
$ go test -vTrong chế độ này, tắt cache kiểm thử. Chế độ còn lại là chế độ danh sách, khi tham số package không rỗng, sẽ thực thi kiểm thử theo chế độ danh sách, khác biệt của nó với cái trước là có bật cache kiểm thử hay không. Ví dụ như các lệnh dưới đây
$ go test -v .
$ go test -v ./...
$ go test .
$ go test -v net/httpTrong chế độ danh sách, go sẽ biên dịch các tệp kiểm thử của từng gói trong gói được chỉ định thành các tệp nhị phân và thực thi, để tránh chạy lặp lại kiểm thử, go mặc định sẽ cache kết quả, khi chạy lần thứ hai sẽ không biên dịch lại. Khi sử dụng các tham số sau sẽ mặc định bật cache
-benchtime-cpu-list-parallel-runshort-timeout-failfast-v
Sử dụng các tham số khác ngoài những tham số này có thể tắt cache, cách làm được官方 khuyến khích là sử dụng -count=1 để tắt cache. Ví dụ
$ go test -v -count=1 ./...Chỉ thị
Khác với lệnh, các chỉ thị của go tồn tại dưới dạng hardcode trong các tệp nguồn, chúng có một tên thuật ngữ khác: chỉ thị biên dịch (progma directives).
Trình biên dịch và linker sẽ thay đổi hành vi của chính chúng do chúng để đạt được hiệu quả kiểm soát biên dịch, giống như macro trong ngôn ngữ c, đương nhiên không phải tất cả các chỉ thị đều dùng để ảnh hưởng đến biên dịch, một phần dùng cho các hành vi chức năng khác, ví dụ chỉ thị generate thường dùng cho chức năng tạo mã. Những chỉ thị này thường tồn tại dưới dạng chú thích, và có tiền tố là //go:, ở giữa không thể chứa bất kỳ khoảng trắng nào, ví dụ chỉ thị //go:generate. Tất cả các loại chỉ thị tổng cộng chia làm hai loại
- Chỉ thị chức năng, đây là các chỉ thị chức năng mà go cung cấp có thể sử dụng tùy ý, ví dụ
generate,embed,build. - Chỉ thị trình biên dịch, loại chỉ thị này cần thận trọng khi sử dụng, sử dụng bừa bãi có thể dẫn đến các kết quả không thể dự đoán được.
Ngoài các chỉ thị chức năng ra, hầu hết các chỉ thị chỉ có thể tác dụng lên các chữ ký hàm. Đối với các chỉ thị trình biên dịch có thể thực thi lệnh go doc compile để xem các chỉ thị của nó. Đối với tất cả các chỉ thị, có thể tìm thấy thông tin liên quan đến chúng trong cmd/compile/internal/ir/node.go: 440.
generate
$ go help generate
usage: go generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]Chỉ thị generate như tên gọi là liên quan đến tạo, thường tác dụng của nó là dùng để thực thi các lệnh sẽ tạo mã và cập nhật mã nguồn, nhưng thực tế nó có thể thực thi bất kỳ lệnh nào. Và, chỉ thị generate khác với các chỉ thị khác, nó có một lệnh chuyên dụng có thể dùng để thực thi tất cả các chỉ thị generate nằm trong các tệp nguồn. Nó có thể dùng tên tệp hoặc tên gói làm tham số đầu vào để biểu thị thực thi các chỉ thị generate của những tệp nào, dưới đây là các tham số khác của nó.
-run=regex, chạy các chỉ thị generate được chỉ định-skip=regex, bỏ qua các chỉ thị generate được chỉ định-n, in ra các lệnh sẽ được thực thi-x, in ra các lệnh được thực thi trong quá trình-v, xuất các tệp được xử lý
Ngoài ra, các lệnh được thực thi trong chỉ thị generate còn hỗ trợ các tham số built-in sau
$GOARCH, kiến trúc cpu$GOOS, hệ điều hành$GOFILE, tên tệp$GOLINE, số dòng$GOPACKAGE, tên gói$GOROOT, go root$DOLLAR, ký hiệu đô la$PATH, biến môi trường path
Xem một ví dụ, không có mã gì chỉ có một dòng chú thích
package main
//go:generate echo "hello world!"Thực thi lệnh
$ go generate .
hello world!Ví dụ này là thực thi lệnh go
package main
//go:generate go versionThực thi lệnh
$ go generate .
go version go1.21.3 windows/amd64Chỉ thị generate có thể dùng để thực thi bất kỳ lệnh nào, ví dụ swagger tạo tài liệu API, hoặc Wire tạo mã IOC. Nhưng chỉ thị này không thích hợp để thực thi các lệnh quá phức tạp, nó thích hợp để thực thi các lệnh ngắn, nếu có yêu cầu phức tạp có thể sử dụng script hoặc makefile để thay thế.
embed
Chỉ thị embed là mới được thêm vào trong 1.16, tác dụng của nó là có thể đóng gói các tệp tĩnh cùng vào trong tệp nhị phân, ví dụ như các mẫu HTML. Định dạng của nó như sau
//go:embed patternpattern có thể là biểu thức glob, cũng có thể là một thư mục hoặc một tệp cụ thể nào đó. Xem một ví dụ
package main
import "embed"
//go:embed *
var static embed.FSChỉ thị embed yêu cầu phải nằm trên một biến toàn cục có kiểu embed.Fs, lưu ý phải là biến toàn cục, và sử dụng nó phải import gói embed, trong ví dụ này, * đại diện cho sẽ đóng gói tất cả các tệp trong thư mục hiện tại vào trong tệp nhị phân, nhưng nó sẽ không cho phép tồn tại các thư mục bắt đầu bằng ..
Ví dụ dưới đây hiển thị đọc nội dung từ các tệp được nhúng
package main
import (
"embed"
"fmt"
)
//go:embed *.txt
var static embed.FS
func main() {
bytes, err := static.ReadFile("hello.txt")
if err != nil {
panic(err)
}
fmt.Println(string(bytes))
}Nó chỉ có ba phương thức, sử dụng không khác biệt gì so với hệ thống tệp thông thường, và vì nó triển khai interface io/Fs, nên cũng có thể được truyền như một đối tượng Fs.
func (f FS) Open(name string) (fs.File, error)
func (f FS) ReadFile(name string) ([]byte, error)
func (f FS) ReadDir(name string) ([]fs.DirEntry, error)Ví dụ dưới đây hiển thị nhúng các tệp html thông qua chỉ thị embed, và truy cập thông qua dịch vụ http.
package main
import (
"embed"
"net/http"
)
//go:embed index.html
var htmlFs embed.FS
func main() {
http.Handle("/", http.FileServer(http.FS(htmlFs)))
http.ListenAndServe(":8080", http.DefaultServeMux)
}Kết quả truy cập như sau
$ curl -s -GET 127.0.0.1:8080
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello world!</title>
</head>
<body>
<H1>Hello World!</H1>
<script>
alert("hello world!");
</script>
</body>
</html>Chỉ thị embed còn hỗ trợ kiểu của biến toàn cục có thể là []byte, ví dụ như ví dụ dưới đây
package main
import (
_ "embed"
"net/http"
)
//go:embed index.html
var rawdata []byte
func main() {
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
writer.Write(rawdata)
})
http.ListenAndServe(":8080", http.DefaultServeMux)
}Hiệu quả mà nó triển khai cũng tương tự như ví dụ trước.
$ curl -s -GET 127.0.0.1:8080
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello world!</title>
</head>
<body>
<H1>Hello World!</H1>
<script>
alert("hello world!");
</script>
</body>
</html>build
Trong phần build-Kiểm soát biên dịch, đã nói đến việc sử dụng chỉ thị // +build để kiểm soát hành vi biên dịch. Còn chỉ thị //go:build là mới ra trong 1.17, với ý định thay thế chỉ thị trước, nhưng hiện tại đã là 1.21 mà vẫn chưa thay thế,估计 sau này sẽ tồn tại dưới dạng cùng tồn tại, về chỉ thị mới này, tài liệu官方 cũng có giới thiệu: build constraints. Chức năng của nó không khác biệt gì so với cái trước, nhưng cú pháp nghiêm ngặt hơn, hỗ trợ biểu thức boolean, xem một ví dụ
//go:build (linux && 386) || (darwin && !cgo)
package pkg_nameCách này có khả năng đọc cao hơn nhiều so với cách trước.
line
Chỉ thị line sẽ ảnh hưởng đến số dòng, số cột, và tên tệp của dòng tiếp theo của nó, tác dụng của nó chỉ có vậy, hầu hết thời gian có thể dùng để gỡ lỗi v.v. Ví dụ khi xảy ra lỗi, sẽ thay đổi thông tin mà trình biên dịch xuất.
package main
var a undefinedType
func main() {
}Trong trường hợp bình thường, trình biên dịch sẽ xuất
.\main.go:3:7: undefined: undefinedTypeNhưng nếu sử dụng chỉ thị line, thì sẽ khác
package main
//line abc.go:10:100
var a undefinedType
func main() {
}Thì kết quả xuất của nó sẽ là
abc.go:10:106: undefined: undefinedTypeVà vì lý do lịch sử, chỉ thị line cũng là chỉ thị duy nhất có cách sử dụng khác với các chỉ thị khác. Định dạng của nó là
//line filename:line:columnCó thể thấy nó không cần go: làm tiền tố.
linkname
Hoạt động của chỉ thị này có thể link các hàm hoặc biến toàn cục của các gói khác, ngay cả khi nó là kiểu riêng tư, thao tác này thường xuất hiện trong thư viện chuẩn đặc biệt là runtime, có một số hàm không có thân hàm được triển khai thông qua cách này, một phần khác các hàm có thân hàm rỗng thì được triển khai bằng hợp ngữ. Xem cách sử dụng của nó, định dạng sử dụng như sau
//go:linkname 链接类型名称 被链接的类型Và trước khi sử dụng, ví dụ import gói unsafe. Xem một ví dụ đơn giản link các kiểu riêng tư trong thư viện chuẩn
import (
"fmt"
"unsafe"
)
//go:linkname memhash runtime.memhash
func memhash(p unsafe.Pointer, h, s uintptr) uintptr
func MemHash(data []byte) uint64 {
ptr := unsafe.Pointer(unsafe.SliceData(data))
return uint64(memhash(ptr, 0, uintptr(len(data))))
}
func main() {
fmt.Println(MemHash([]byte("hello")))
}Kết quả xuất
15395306441938000233Nó đã link hàm riêng tư runtime.memhash với hàm mà chúng ta tự khai báo, hàm này không có thân hàm chỉ có một chữ ký, chỉ đóng vai trò là một vật mang. Tác dụng của memhash là给定 một con trỏ, hạt giống hash, và độ lệch bộ nhớ, tính toán giá trị hash dựa trên bộ nhớ. Quá trình link này được hoàn thành trong thời gian biên dịch,
Nếu không phải là thư viện chuẩn, thì tình hình sẽ có chút khác biệt, ví dụ trong gói example có một hàm test, trước khi link trước hết phải import ẩn danh gói này.
package example
// 一个私有类型,外界无法访问。
func test() string {
return "a"
}package main
import (
"fmt"
_ "golearn/example"
_ "unsafe"
)
//go:linkname test golearn/example.test
func test() string
func main() {
fmt.Println(test())
}Kết quả xuất
aCó thể thấy đã link thành công, phương pháp này có thể vượt qua hệ thống mô-đun của go để làm bất cứ điều gì, nhưng không khuyến nghị sử dụng quy mô lớn, trừ khi bạn biết mình đang làm gì.
noinline
Chỉ thị noinline biểu thị một hàm bị cấm tối ưu hóa inline, ngay cả khi nó rất đơn giản. Xem một ví dụ đơn giản
package main
func val() string {
return "val"
}
func main() {
var c = val()
_ = c
}val là một hàm rất đơn giản, tác dụng của nó là trả về một ký tự chuỗi, vì nó quá đơn giản và kết quả luôn có thể dự đoán được, thì trong thời gian biên dịch nó sẽ được trình biên dịch tối ưu hóa thành dạng sau
package main
func main() {
var c = "val"
_ = c
}Xem dạng hợp ngữ của nó, có thể thấy không phát hiện cuộc gọi của hàm val.
TEXT main.val(SB), NOSPLIT|NOFRAME|ABIInternal, $0-0
FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
FUNCDATA $1, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
LEAQ go:string."val"(SB), AX
MOVL $3, BX
FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
RETTiếp theo thêm chỉ thị noinline
package main
//go:noinline
func val() string {
return "val"
}
func main() {
var c = val()
_ = c
}Xem lại dạng hợp ngữ của nó
CMPQ SP, 16(R14)
PCDATA $0, $-2
JLS 17
PCDATA $0, $-1
PUSHQ BP
MOVQ SP, BP
FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
FUNCDATA $1, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
PCDATA $1, $0
CALL main.val(SB)
POPQ BP
RETLần này có thể thấy rất rõ cuộc gọi main.val này, và đây cũng chính là chức năng mà chỉ thị noinline phát huy, ngăn chặn inline hàm khi trình biên dịch tối ưu hóa.
nospilit
Tác dụng của chỉ thị nospilit là bỏ qua phát hiện tràn stack. Vì mô hình lập lịch đồng thời của go là lập lịch抢占式, giả sử một hàm sẽ chạy mã rất底层, các goroutine khác khi gọi hàm này không thích hợp bị抢占, có thể sử dụng chỉ thị này để biểu thị.
//go:nosplit
func nospilitFn()Sau khi sử dụng chỉ thị này, cũng sẽ không còn tăng trưởng stack.
noescape
noescape, thông qua tên của nó có thể dễ dàng đoán được là liên quan đến escape, tác dụng của nó là biểu thị hàm hiện tại sẽ không xảy ra hành vi escape bộ nhớ, sau khi thực thi xong tất cả các tài nguyên đều được thu hồi, và hàm này phải chỉ có chữ ký không có thân hàm, trong trường hợp này nói chung việc triển khai hàm được thực hiện bằng hợp ngữ.
Ví dụ memhash đã sử dụng trước đó sẽ sử dụng chỉ thị này
//go:noescape
//go:linkname memhash runtime.memhash
func memhash(p unsafe.Pointer, h, s uintptr) uintptrNhư vậy, trình biên dịch sẽ không thực hiện phân tích escape cho nó, điều kiện tiên quyết là bạn phải đảm bảo nó sẽ không xảy ra escape, nếu xảy ra, thì không biết sẽ có hậu quả gì.
uintptrescapes
Chỉ thị uintptrescapes biểu thị các tham số kiểu uinptr trong hàm này được chuyển thành giá trị con trỏ và escape vào heap, và phải giữ chúng sống. Chỉ thị này nói chung dùng cho một số cuộc gọi hệ thống底层, trong hầu hết các trường hợp không cần phải tìm hiểu nó.
//go:uintptrescapes
func nospilit(ptr uintptr) uintptrTrước đây应该 còn có một chỉ thị notinheaps dùng để biểu thị một kiểu không cho phép phân bổ bộ nhớ trên heap, không biết đã bị xóa trong phiên bản nào.
norace
Chỉ thị norace biểu thị việc truy cập bộ nhớ của một hàm không cần phân tích race condition, thường là khi chạy mã底层 không thích hợp để thực hiện phân tích race condition.
//go:norace
func low_level_code(ptr uintptr) uintptrTIP
Còn có một số chỉ thị bị hạn chế chỉ có thể được sử dụng bởi gói runtime, bên ngoài không thể sử dụng, chúng sẽ liên quan đến những thứ sâu hơn, muốn tìm hiểu có thể xem giới thiệu liên quan đến chúng trong Runtime-only compiler directives.
