go 代码组织
go 程序组成package, 一个package是一组在相同目录的源代码共同编译而成。在同一个包里,函数、类型、变量、和常量是彼此可见的。一系列相关的包组成了module。一个repo包含一个或者多个module。
GOPATH & GOBIN
go build生成bin文件,如果GOBIN未设置,则安装到GOPATH。如果设置了GOBIN,则安装到GOBIN。
% mkdir first-go-module
% cd first-go-module
% # init a module, module path example/user/hello
% go mod init example/user/hello
go: creating new go.mod: module example/user/hello
% ls -al
total 8
drwxr-xr-x 3 carawang staff 96 Aug 19 21:17 .
drwxr-xr-x 3 carawang staff 96 Aug 19 21:15 ..
-rw-r--r-- 1 carawang staff 37 Aug 19 21:17 go.mod
% # module name has been set.
% cat go.mod
module example/user/hello
go 1.21.5
% mkdir -p example/user/hello
% vi example/user/hello/hello.go
% cat example/user/hello/hello.go
package main
import "fmt"
func main() {
fmt.Println("Hello, world.")
}
% # go install = go build + install bin 文件到GOPATH/GOBIN
% go install example/user/hello/hello.go
% # 如果GOBIN没有设置,则安装到GOPATH
% go env GOBIN
% go env GOPATH
/Users/carawang/go
% ls -al /Users/carawang/go/bin
total 92368
drwxr-xr-x 5 carawang staff 160 Aug 19 21:36 .
drwxr-xr-x 4 carawang staff 128 Aug 19 11:42 ..
-rwxr-xr-x 1 carawang staff 31280288 Aug 19 11:42 gopls
-rwxr-xr-x 1 carawang staff 1911088 Aug 19 21:36 hello
-rwxr-xr-x 1 carawang staff 14097632 Aug 19 11:43 staticcheck
% date
Mon Aug 19 21:36:59 CST 2024
% export PATH=$PATH:/Users/carawang/go/bin
% hello
Hello, world.
% mkdir bin
% export GOBIN=/Users/carawang/learn-kubebuilder/first-go-module/bin
% go install example/user/hello/hello.go
% # 设置了GOBIN,则会安装在GOBIN
% ls -al bin
total 3736
drwxr-xr-x 3 carawang staff 96 Aug 19 21:38 .
drwxr-xr-x 6 carawang staff 192 Aug 19 21:38 ..
-rwxr-xr-x 1 carawang staff 1911088 Aug 19 21:38 hello
carawang@carawangs-MacBook-Pro first-go-module % go env -u GOBIN
go: reading go env config: open /Users/carawang/Library/Application Support/go/env: no such file or directory
carawang@carawangs-MacBook-Pro first-go-module % touch /Users/carawang/Library/Application\ Support/go/env
carawang@carawangs-MacBook-Pro first-go-module % go env -u GOBIN
GOROOT & go install module
在做GOPATH&GOBIN的实验时,我们是使用go install *.go去直接指定module go文件,这里我们试验下直接install module。
% go env GOPATH
/Users/carawang/go
% # 我们将module挪到了GOPATH的src路径下
% pwd
/Users/carawang/go/src
% tree
.
├── example
│ └── user
│ └── hello
│ └── hello.go
└── go.mod
4 directories, 2 files
% # go help install中有这样一段话:当禁用模块感知模式(GO111MODULE)时,非主包将安装在目录 $GOPATH/pkg/$GOOS_$GOARCH 中。当启用模块感知模式时,非主包将被构建和缓存,但不会安装。实际情况是,当它on的时候,会遇到错误std。关闭它则可正常安装
% go env GO111MODULE
off
% hello
Hello, World!
% go env -w GO111MODULE=on
% go install example/user/hello
package example/user/hello is not in std (/usr/local/Cellar/go/1.21.5/libexec/src/example/user/hello)
这里我们看到我们打开GO111MODULE,安装我们自己的包就会报错。
这个错误的意思是:GOROOT路径(go的安装根路径:/usr/local/Cellar/go/1.21.5/libexec/)下没有example/user/hello。 而关闭这个,我们就可以安装我们的module到GOPATH下。
可见,GO111MODULE的值影响了go查找和安装包的路径。理解GOROOT和GOPATH对我来说有点繁琐。我的实践是,直接将其设置成off,就很好用。
自定义的模块引用
我门在hello module中引用一个morestring的module,使其可以进行转译。
% # 查看reverse.go, hello.go和go.mod
% cat example/user/hello/morestrings/reverse.go
// Package morestrings implements additional functions to manipulate UTF-8
// encoded strings, beyond what is provided in the standard "strings" package.
package morestrings
// ReverseRunes returns its argument string reversed rune-wise left to right.
func ReverseRunes(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
% cat example/user/hello/hello.go
package main
import (
"fmt"
"example/user/hello/morestrings"
)
func main() {
fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
}
carawang@carawangs-MacBook-Pro src % cat go.mod
module example/user/hello
% pwd
/Users/carawang/go/src
% tree
.
├── example
│ └── user
│ └── hello
│ ├── hello.go
│ └── morestrings
│ └── reverse.go
└── go.mod
go 1.21.5
% cd example/user/hello/morestrings
% go build
% cd -
% go install example/user/hello
% hello
Hello, Go!
引用第三方模块
我们在hello.go中引入cmp第三方包
% cat example/user/hello/hello.go
package main
import (
"fmt"
"example/user/hello/morestrings"
"github.com/google/go-cmp/cmp"
)
func main() {
fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
fmt.Println(cmp.Diff("Hello World", "Hello Go"))
}
因为我们关闭了GO111MODULE功能,这里我们需要使用一下go get进行下载和安装
% cat example/user/hello/hello.go
package main
import (
"fmt"
"example/user/hello/morestrings"
"github.com/google/go-cmp/cmp"
)
func main() {
fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
fmt.Println(cmp.Diff("Hello World", "Hello Go"))
}
% tree
.
├── example
│ └── user
│ └── hello
│ ├── hello.go
│ └── morestrings
│ └── reverse.go
└── go.mod
% go get "github.com/google/go-cmp/cmp"
% ls -al
total 8
drwxr-xr-x 5 carawang staff 160 Aug 20 15:33 .
drwxr-xr-x 5 carawang staff 160 Aug 20 14:04 ..
drwxr-xr-x 3 carawang staff 96 Aug 20 14:17 example
drwxr-xr-x 3 carawang staff 96 Aug 20 15:33 github.com
-rw-r--r-- 1 carawang staff 78 Aug 20 14:55 go.mod
% go install example/user/hello
carawang@carawangs-MacBook-Pro src % hello
Hello, Go!
string(
- "Hello World",
+ "Hello Go",
)
% ls -al
total 8
drwxr-xr-x 5 carawang staff 160 Aug 20 15:33 .
drwxr-xr-x 5 carawang staff 160 Aug 20 14:04 ..
drwxr-xr-x 3 carawang staff 96 Aug 20 14:17 example
drwxr-xr-x 3 carawang staff 96 Aug 20 15:33 github.com
-rw-r--r-- 1 carawang staff 78 Aug 20 14:55 go.mod
% cat go.mod
module example/user/hello
go 1.21.5
require github.com/google/go-cmp v0.6.0
我们看到第三包也下载了GOPATH的src路径下。这样我们就只和GOPATH打交道了。