go语言简述
0. 简述
Go是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。
Go语言被设计成一门应用于搭建web服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。对于高性能分布式系统领域而言,Go语言无疑比大多数其他语言有着更高的开发效率。它提供了海量并行的支持,这对于游戏服务器端的开发而言是再好不过的。
Go官网:https://golang.google.cn/或https://github.com/golang/go
标准库: https://golang.google.cn/pkg/ https://godoc.org/
package main import "fmt" func main() { fmt.Println("Hello, World!") }
X86上编译运行:
wang@ubuntu:~/go$ go build -o hello hello.go wang@ubuntu:~/go$ ./hello Hello, World!
或直接运行
wang@ubuntu:~/go$ go run hello.go
Hello, World!
X86平台交叉编译ARM64平台上程序:
GOOS=linux GOARCH=arm64 go build -o hello hello.go wang@ubuntu:~/go$ file hello hello: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, not stripped
godoc用法:
godoc -http=localhost:6060 -play
godoc可提供离线的go文档,便于本地查看。
可在https://godoc.org/中搜索所有golang库的接口说明。
1. Go编译器
两种官方编译器,gc和gccgo,其中gccgo基于gcc后端。
go编译器支持8种指令集,不同建构编译质量不同:
amd64 (also known as x86-64)
386 (x86 or x86-32) Comparable to the amd64 port.
arm (ARM)
Supports Linux, FreeBSD, NetBSD, OpenBSD and Darwin binaries. Less widely used than the other ports.
arm64 (AArch64)
Supports Linux and Darwin binaries. New in 1.5 and not as well exercised as other ports.
ppc64, ppc64le (64-bit PowerPC big- and little-endian)
Supports Linux binaries. New in 1.5 and not as well exercised as other ports.
mips, mipsle (32-bit MIPS big- and little-endian)
Supports Linux binaries. New in 1.8 and not as well exercised as other ports.
mips64, mips64le (64-bit MIPS big- and little-endian)
Supports Linux binaries. New in 1.6 and not as well exercised as other ports.
s390x (IBM System z)
Supports Linux binaries. New in 1.7 and not as well exercised as other ports.
go编译环境可以被定制,与平台和建构相关的是$GOOS和$GOARCH,分别指定目标操作系统和目标建构。常用组合如下:(注:$GOOS是darwin for macOS 10.1及以上和iOS)
$GOOS $GOARCH
android arm
darwin 386
darwin amd64
darwin arm
darwin arm64
linux 386
linux amd64
linux arm
linux arm64
windows 386
windows amd64
go编译器(或go环境)安装
有两种安装方式:二进制发布包和源码包,参考https://golang.google.cn/doc/install。一般情况下可直接下载二进制发布包,官方已提供了常用平台的二进制发布包。
下载二进制tar包,tar -C /usr/local -xzf go$VERSION.$OS-$ARCH.tar.gz,一般安装路径为/usr/local,go工具命令要执行需要将/usr/local/go/bin导出到PATH环境变量中(/etc/profile可长期有效)。
源码包安装方式参考:Installing Go from source
ubuntu下可直接apt安装:
sudo apt-get install golang-go
go卸载
linux下直接删除/usr/local/go目录即可(同时修改PATH环境变量,或/etc/profile)。
GO环境变量
go env可打印go环境变量。
tee -a $HOME/.bashrc <<'EOF' # Go envs export GOVERSION=go1.17.2 # Go 版本设置 export GO_INSTALL_DIR=$HOME/go # Go 安装目录 export GOROOT=$GO_INSTALL_DIR/$GOVERSION # GOROOT 设置 export GOPATH=$WORKSPACE/golang # GOPATH 设置 export PATH=$GOROOT/bin:$GOPATH/bin:$PATH # 将 Go 语言自带的和通过 go install 安装的二进制文件加入到 PATH 路径中 export GO111MODULE="on" # 开启 Go moudles 特性 export GOPROXY=https://goproxy.cn,direct # 安装 Go 模块时,代理服务器设置 export GOPRIVATE= export GOSUMDB=off # 关闭校验 Go 依赖包的哈希值 EOF
Go 默认已经不需要配置任何环境变量了——什么 GOROOT、GOPATH 等都不需要了。但是PATH和GOPROXY还需要在~/.bash_profile指定下。
export PATH=$PATH:/usr/local/go/bin export GOPROXY=https://goproxy.cn,https://goproxy.io,direct
##############################如下环境变量可忽略!!!
$GOPATH
GOPATH指定workspace位置,默认为$home/go,go项目在本地的开发环境的项目根路径(以便项目编译,go build, go install,go get)。若工作在其他目录,需设定GOPATH。export GOPATH=$HOME/go
或直接写到/etc/profile中,然后source /etc/profile
注意GOPATH不能和go安装目录相同。
go env GOPATH
打印当前有效的GOPATH,若没有设置打印默认位置。
For convenience, add the workspace's bin subdirectory to your PATH:
$ export PATH=$PATH:$(go env GOPATH)/bin
GOPATH之下主要包含三个目录:bin,pkg,src。bin目录主要存放可执行文件;pkg目录存放编译好的库文件,主要是*.a文件;src目录下主要存放go的源文件。
$GOROOT
go的安装目录,配置后不会更改。一般为/usr/local/go或/usr/go或/usr/lib/go。
$GOROOT_FINAL
$GOOS and $GOARCH
用于不同平台的交叉编译,只需要在build之前设置这两个变量即可,这也是go语言的优势之一:可以编译生成跨平台运行的可执行文件。
注意:这个交叉编译暂不支持cgo方式,因此交叉编译时需要设置$CGO_ENABLED设置为0。
$GOHOSTOS and $GOHOSTARCH
$GOBIN
go二进制文件安装目录,默认为$GOROOT/bin。
$GO386
$GOARM
$GOMIPS
集成开发环境IDE
vscode-golang配置参考:VS code golang 开发环境搭建 VSCode 开发 Go 程序也可以和 GoLand 一样强大--polarisxu
2. cgo
Cgo lets Go packages call C code.
The basics
If a Go source file imports "C"
, it is using cgo. The Go file will have access to anything appearing in the comment immediately preceding the line import "C"
, and will be linked against all other cgo comments in other Go files, and all C files included in the build process.
Note that there must be no blank lines in between the cgo comment and the import statement.
To access a symbol originating from the C side, use the package name C
. That is, if you want to call the C function printf()
from Go code, you write C.printf()
. Since variable argument methods like printf aren't supported yet (issue 975), we will wrap it in the C method "myprint":
package main
/*
#include <stdio.h>
#include <stdlib.h>
void myprint(char* s) {
printf("%s", s);
}
*/
import "C"
import "unsafe"
func main() {
cs := C.CString("Hello from stdio\n")
C.myprint(cs)
C.free(unsafe.Pointer(cs))
}
参考:
1. http://golang.org/doc/articles/c_go_cgo.html
2. https://github.com/golang/go/wiki/cgo
3. http://wiki.jikexueyuan.com/project/go-command-tutorial/0.13.html 极客学院go命令详解
4. https://books.studygolang.com/advanced-go-programming-book/ch2-cgo/readme.html Go语言高级编程(Advanced Go Programming)cgo编程
3. Go交叉编译
If cgo is not required (common go programs, not including c/c++)
The go tool won’t require any bootstrapping if cgo is not required. That allows you to target the following program to any GOOS/GOARCH without requiring you to do any additional work. Invoke go build.
$ cat main.go
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
In order to target android/arm, run the following command.
$ GOOS=android GOARCH=arm GOARM=7 go build .
The produced binary is targeting ARMv7 processors that runs Android. All possible GOOS and GOARCH values are listed on the environment docs.
If cgo is required (including c/c++)
If you need to have cgo enabled, the go tool allows you to provide custom C and C++ compilers via CC and CXX environment variables.
$ CGO_ENABLED=1 CC=android-armeabi-gcc CXX=android-armeabi-g++ \
GOOS=android GOARCH=arm GOARM=7 go build .
The toolchain will invoke android-armeabi-gcc and android-armeabi-g++ if it is required to compile any part of the package with a C or C++ compiler. Consider the following program with a slightly different main function. Rather than outputting “hello world” to the standard I/O, it will use Android system libraries to write “hello world” to the system log.
$ cat main.go
// +build android
package main
// #cgo LDFLAGS: -llog
//
// #include <android/log.h>
//
// void hello() {
// __android_log_print(
// ANDROID_LOG_INFO, "MyProgram", "hello world");
// }
import "C"
func main() {
C.hello()
}
If you build the program with the command above and examine the build with -x, you can observe that cgo is delegating the C compilation to arm-linux-androideabi-gcc.
$ CGO_ENABLED=1 \
CC=arm-linux-androideabi-gcc \
CXX=arm-linux-androideabi-g++ \
GOOS=android GOARCH=arm GOARM=7 go build -x .
...
CGO_LDFLAGS=”-g” “-O2” “-llog” /Users/jbd/go/pkg/tool/darwin_amd64/cgo -objdir $WORK/github.com/rakyll/hello/_obj/ -importpath github.com/rakyll/hello — -I $WORK/github.com/rakyll/hello/_obj/ main.go
arm-linux-androideabi-gcc -I . -fPIC -marm -pthread -fmessage-length=0 -print-libgcc-file-name
arm-linux-androideabi-gcc -I . -fPIC -marm -pthread -fmessage-length=0 -I $WORK/github.com/rakyll/hello/_obj/ -g -O2 -o $WORK/github.com/rakyll/hello/_obj/_cgo_main.o -c $WORK/github.com/rakyll/hello/_obj/_cgo_main.c
...
Pre-building the standard library
The go tool also provides a utility if you would like to pre-build the standard library, targeting a specific GOOS and GOARCH.
$ CGO_ENABLED=1 \
CC=arm-linux-androideabi-gcc \
CXX=arm-linux-androideabi-g++ \
GOOS=android GOARCH=arm GOARM=7 go install std
The standard library targeting android/armv7 will be available at $GOROOT/pkg/android_arm.
$ ls $GOROOT/pkg/android_arm
archive fmt.a math runtime.a
bufio.a go math.a sort.a
bytes.a hash mime strconv.a
compress hash.a mime.a strings.a
container html net sync
crypto html.a net.a sync.a
crypto.a image os syscall.a
database image.a os.a testing
debug index path testing.a
encoding internal path.a text
encoding.a io reflect.a time.a
errors.a io.a regexp unicode
expvar.a log regexp.a unicode.a
flag.a log.a runtime
If you prefer not to pre-build and install the standard library to the GOROOT, required libraries will be built while building user packages. But, the standard libraries builds are not preserved for future use at this stage and they will be rebuilt each time you run go build.
4. golang代理
由于网络限制,一般要使用代理获取仓库。
golang代理使用proxy.cn,参考:https://github.com/goproxy/goproxy.cn/blob/master/README.zh-CN.md
使用方法:
$ export GOPROXY=https://goproxy.cn,https://goproxy.io,direct
或
$ export GO111MODULE=on
$ export GOPROXY=https://goproxy.cn,https://goproxy.io,direct
或直接写入:~/.bash_profile
5. go命令工具
可通过go help获取go命令,如下记录一些易忽略的go命令用法。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
https://github.com/golang/tools.git提供了golang内置的工具,有些会在golang二进制安装包中,如vet,godoc等,可通过如下命令安装:
包含工具unmarshal/stress/stringer/stingintconv/shadow/guru/godex/goimports/eg/cover/bundle等。
go get -u golang.org/x/tools/...
1) go build
缩小输出文件体积
go 编译出的文件,体积挺大的。一个重要原因是其中包含了调试信息,可以通过编译参数使其不包含调试信息。
# 移除 调试信息(-w) 和 符号表(-s) go build -o main -ldflags "-w -s" main.go
上述操作使用 -ldflags
参数指定 -w
和 -s
, 分别表示在编译时不包含调试信息和符号表,此举可以较好地缩减二进制文件体积。
编译时写入全局变量
go 可以通过编译参数,在编译时对变量进行赋值。一般情况下,这种操作可以让程序保留编译信息等数据。
通过 -ldflags
参数,设定 -X
操作,可以为全局变量赋值(一定要加-X)。
go build -ldflags "-X 'main.BuildTime=time006'" main.go go build -ldflags "-X 'main.BuildTime=`date`' -X 'main.GitHash=`git rev-parse HEAD`'" main.go go build -ldflags "-X cnca.HTTP2ClientTLSCAPath=/etc/openness/certs/ngc" -o "kubectl-cnca"
2) gofmt
统一的代码格式化工具
3) goimports
自动import依赖包工具,也对代码进行格式化,等于gofmt加上依赖包管理。
goimports -l -d -v -w .
4) go vet
内置错误检查工具
5) golint
静态代码检测工具。
6) golangci-lint
静态代码质量检测工具,用于包的质量分析。go代码检查聚合工具,可定制。
golint
进行静态检查(或者同时使用 golint
和 golangci-lint),在其他的项目中使用可定制化的 golangci-lint
来进行静态检查,因为在基础库和框架中施加强限制对于整体的代码质量有着更大的收益。推荐Go 项目中使用 golint
+ golangci-lint
并开启全部的检查尽量尽早发现代码中包含文档在内的全部缺陷。
代码检查应用
细看Kubernetes库,会发现,其会针对每个PR都做如下静态检查:
- gofmt: https://github.com/kubernetes/kubernetes/blob/master/hack/verify-gofmt.sh
- govet: https://github.com/kubernetes/kubernetes/blob/master/hack/make-rules/vet.sh
- golint: https://github.com/kubernetes/kubernetes/blob/master/hack/verify-golint.sh
因为golint只是纠正代码风格,并不是强制,所以k8s官方就弄了比较软的方案,对于当前已经存在的代码如果有问题,先排除掉(如下)。对于新生代码,如果检查失败,ci就挂掉。
https://github.com/kubernetes/kubernetes/blob/master/hack/.golint_failures
Kubernetes只利用了官方的几款工具, 在检测准确性上比较有保障。有了这些检查点,也能倒逼研发人员关注提交代码的质量,会迫使其在本地或者IDE上就配置好检查,确保每次提交的PR都能通过检查,不浪费CI资源。这也是合格工程师的基本要求。
go语言学习参考:
1. Go 系列教程(Golang tutorial series) go语言中文网
2. go入门指南 博客
3. go语言学习 博客
6. https://github.com/golang/go
7. How to write Go Code https://golang.google.cn/doc/code.html
8. https://golang.google.cn/ 提供go在线测试环境和文档
9. https://golang.google.cn/doc/ go相关文档
10. https://golang.google.cn/pkg/ go标准库
11. https://godoc.org/ go实用库搜索
12. https://books.studygolang.com/advanced-go-programming-book/ch2-cgo/readme.html Go语言高级编程(Advanced Go Programming)
13. 在 GitHub 上构建一个看上去正规的 Golang 项目
14. Go 语言设计与实现
15. 细节优化及课程总结,Go并发编程案例解析教程-慕课网
16. Golang标准库文档 中文文档
17. https://books.studygolang.com/The-Golang-Standard-Library-by-Example/ go语言中文网 标准库 示例
18. 如何写出优雅的 Go 语言代码
19. GO 命令教程 https://wiki.jikexueyuan.com/project/go-command-tutorial/