0、和java一樣,go也是跨平臺,天生支持Unicode。但是go直接生成可執行文件,性能更高,內存佔用少。但是又和java一樣,go打出來的二進制包能夠掃描到依賴的庫,如果庫有漏洞,安全掃描會被掃出來。
1、安裝、環境配置及術語
從https://golang.google.cn/下載對應的版本。
使用命令行go env可以查看,如下:
[lightdb@lightdb-dev ~]$ go env GO111MODULE="" #設置是否打開go modules,auto/on/off三個取值,1.13開始默認,1.14開始推薦 GOARCH="amd64" GOBIN="" # go install最終拷貝到的目錄,一般go程序打成tar.gz分發,所以關係不大,配置的話指向$GOPATH/bin GOCACHE="/home/lightdb/.cache/go-build" GOENV="/home/lightdb/.config/go/env" GOEXE="" GOEXPERIMENT="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOINSECURE="" GOMODCACHE="/home/lightdb/go/pkg/mod" GONOPROXY="" GONOSUMDB="" GOOS="linux" GOPATH="/home/lightdb/go" # 項目的根目錄,最重要的環境變量 GOPRIVATE="" GOPROXY="https://goproxy.cn,direct" # GOPROXY是用來設置go mod的代理,以英文逗號“,”分割,使Go在後續拉取模塊版本時能夠脫離傳統的VCS方式從鏡像站點快速拉取。它擁有一個默認:https://proxy.golang.org,direct,但proxy.golang.org在中國無法訪問,所以建議使用goproxy.cn替代 GOROOT="/usr/lib/golang" # golang的安裝目錄,跟JAVA_HOME一樣 GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/usr/lib/golang/pkg/tool/linux_amd64" GOVCS="" GOVERSION="go1.20.6" GCCGO="gccgo" GOAMD64="v1" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="/dev/null" GOWORK="" CGO_CFLAGS="-O2 -g" CGO_CPPFLAGS="" CGO_CXXFLAGS="-O2 -g" CGO_FFLAGS="-O2 -g" CGO_LDFLAGS="-O2 -g" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build261630818=/tmp/go-build -gno-record-gcc-switches"
hello world驗證環境及熟悉目錄
[lightdb@lightdb-dev go]$ cd src/example/
[lightdb@lightdb-dev example]$ go mod init
[lightdb@lightdb-dev go]$ go run src/example/first.go 123 hello world 65 12.345 [lightdb@lightdb-dev go]$ pwd /home/lightdb/go [lightdb@lightdb-dev go]$
[lightdb@lightdb-dev bin]$ export | grep GO declare -x GOBIN="//home/lightdb/go/bin" declare -x GOPATH="/home/lightdb/go" declare -x GOROOT="//home/lightdb/go/go"
這樣腳手架就可以運行了。
[lightdb@lightdb-dev src]$ cd go-web/
[lightdb@lightdb-dev go-web]$ go build ginweb.go # go build也是個很大的範疇,可以參考https://blog.csdn.net/wan212000/article/details/124288970
相關的報錯及原因和解決辦法如下:
[lightdb@lightdb-dev go]$ go build go: go.mod file not found in current directory or any parent directory; see 'go help modules' [lightdb@lightdb-dev go]$ go mod init # 理論上go mod init即可 go: cannot determine module path for source directory /home/lightdb/go (outside GOPATH, module path must be specified) Example usage: 'go mod init example.com/m' to initialize a v0 or v1 module 'go mod init example.com/m/v2' to initialize a v2 module Run 'go help mod init' for more information. [lightdb@lightdb-dev go]$ go mod init example.com/m # 可以提前預建目錄,這樣cd dir; go mod init即可,不用指定名稱 go: creating new go.mod: module example.com/m go: to add module requirements and sums: go mod tidy [lightdb@lightdb-dev go]$ go build $GOPATH/go.mod exists but should not # 使用go module模塊化機制後,go.mod需要放在具體的模塊中而非在GOPATH目錄下,如$GOPATH/src/example/go.mod,再運行即可 [lightdb@lightdb-dev go]$ go install $GOPATH/go.mod exists but should not
[lightdb@lightdb-dev go]$ go run src/go-web/ginweb.go src/go-web/ginweb.go:7:2: no required module provides package github.com/gin-gonic/gin: go.mod file not found in current directory or any parent directory; see 'go help modules' src/go-web/ginweb.go:5:2: package tool/controller is not in GOROOT (/usr/lib/golang/src/tool/controller) # 需要在模塊的根目錄下打包和運行
package first is not in GOROOT (/usr/lib/golang/src/first) # 在$GOPATH目錄下執行 ln -s /usr/lib/golang go
1.1 主要文件
go.mod Go Modules 的核心文件,包含module、require、replace 和 exclude 4部分。
go.sum 供 Go 命令在構建時判斷依賴包是否合法
詳見https://zhuanlan.zhihu.com/p/635696935,講得很清楚了。
1.2 依賴關係
和java一樣,go的依賴管理也經過了多次構造,最新爲2019年的go mode。
模塊是go管理依賴的基本單元,模塊由多個package組成。go.mod 文件定義了模塊的名稱及其依賴包,通過導入路徑和版本描述一個依賴。
[lightdb@lightdb-dev go]$ go help modules Modules are how Go manages dependencies. A module is a collection of packages that are released, versioned, and distributed together. Modules may be downloaded directly from version control repositories or from module proxy servers. For a series of tutorials on modules, see https://golang.org/doc/tutorial/create-module. For a detailed reference on modules, see https://golang.org/ref/mod. By default, the go command may download modules from https://proxy.golang.org. It may authenticate modules using the checksum database at https://sum.golang.org. Both services are operated by the Go team at Google. The privacy policies for these services are available at https://proxy.golang.org/privacy and https://sum.golang.org/privacy, respectively. The go command's download behavior may be configured using GOPROXY, GOSUMDB, GOPRIVATE, and other environment variables. See 'go help environment' and https://golang.org/ref/mod#private-module-privacy for more information.
2、IDE配置(vscode爲例)及調試
vscode支持遠程開發和本地開發,attach/launch都一樣,都支持本地和遠程。所以除非要訪問linux資源,否則直接windows開發也可以,這和c/c++語言需要依賴很多posix兼容庫如pthread.h/uinstd.h/sys/select.h等具有很大的差別。
2.1 工程結構推薦
一般來說,一個公司多個模塊,下面的結構就行。
GOPATH #環境變量配置 bin pkg src com.xxx 頂級域名作爲區分,便於和三方引入包保持一致 lightdb main.go base service1 service2 unisql main.go base service1 service2 infra module1 module2
go以包爲組織單位,雖然分目錄,但包名和目錄名不一定要相同(只是習慣上最後一層相同),而且包是單層如packageName而非com.xxx.packageName。一個文件夾下的所有文件必須具有相同的包名聲明。
import的是路徑名而非包名(因爲一個目錄下的所有文件需要聲明爲一個包,所以import目錄就相當於import包),引用的是GOPATH(跟CLASSPATH很像)開始的相對路徑。需要注意的是如果目錄裏面有子目錄,則不是同一個包,這個和java是一樣的。
如果多個目錄下存在同名的package(這可是必不可免的),需要在import這些目錄時爲每個目錄指定一個package的別名。
2.2、代碼輔助、跳轉及格式化配置
2.3、debug和attach配置
3、基本概念
每個 Go 程序都是由包構成的。程序從 main
包開始運行。
一個程序中可以有很多main包,這個main包之間無法相互調用,運行時通過go run xxx.go運行。
"math/rand"
包中的源碼均以 package rand
語句開始。
go裏面只有包和函數級別的變量,不存在對象級別。 也就是沒有對象。
go裏面,類型名在變量名之後,函數返回值在最後(這和java/c++相反),如下:
package main import "fmt" func add(x int, y int) int { // 有點類似scala,和java/c都不一樣 return x + y } func main() { fmt.Println(add(42, 13)) }
函數可以返回多值,這個和主流編程語言(如java/c/c++)存在明顯的差異,雖然c++在<utility>中支持返回pair帶兩個值。
支持string、bool和無符號類型(和java/c的差別,java不支持無符號,c在17之前不支持布爾,一般模式typedef定義1和0來模擬),類型轉換需要強制寫,比如int到float,跟postgresql的強類型一樣。而且轉換是函數調用式的語法target_type(src_val)而不是java/c裏面的(target_type) src_val。如下:
package main import ( "fmt" "math" ) func main() { var x, y int = 3, 4 var f float64 = math.Sqrt(float64(x*x + y*y)) // float64是類型轉換 var z uint = uint(f) fmt.Println(x, y, z) }
for/if/else/switch更像是pl/sql的用法加上另外一半的c/c++/java,必須大括號、條件不必強制括號,switch不用帶break(因爲內置)。支持將某個語句延遲到函數調用(defer)返回後在執行(有點aop after的概念哈)
package main import "fmt" func main() { defer fmt.Println("world") fmt.Println("hello") }
函數內外語句使用差異明顯,var和:=
package main import "fmt" func main() { var i, j int = 1, 2 k := 3 // 函數外的每個語句都必須以關鍵字開始(var, func 等等),因此 := 結構不能在函數外使用。 c, python, java := true, false, "no!" fmt.Println(i, j, k, c, python, java) }
包成員可見性,大寫字母開頭爲默認導出,小寫則不導出,因爲大部分開發喜歡默認小寫標識符,所以其實對於控制可訪問性設計比java/c++可更妥些。
init()函數
和c/c++裏面dlopen()加載so文件後自動執行_init()函數一樣,init()函數在每次import一個包後自動執行。如果import相互依賴,也不會重複加載,每個包只會被初始化一次。
基本類型以外的高級數據類型
指針(雖然支持,但基本不推薦使用,除非爲了效率),go中非簡單類型也是傳值、並且沒有對象java的概念,沒有c++的傳引用,所以指針不可避免還是會用的多。
結構體(go不支持類,結構體上支持定義方法),結構體上的方法(按照go官方說法:方法只是個帶接收者參數的函數)語法略微怪異,如下:
package main import ( "fmt" "math" ) type Vertex struct { X, Y float64 } func (v Vertex) Abs() float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) } func main() { v := Vertex{3, 4} fmt.Println(v.Abs()) }
支持接口類型(也就是interface的概念)
type Abser interface { Abs() float64 }
可變長度數組(切片實現,也支持數組的數組)
map(原生支持)
支持函數作爲參數和返回值(像函數指針或c++裏面的function對象),此時函數支持閉包的概念(其實就是中間變量)。
上面兩點更像c with object
協程(goroutine和channel):併發的核心是:不用使用共享內存來通信,而是用通信(channel)來共享內存。
5、go自動化迴歸單元測試
默認情況下,go的單元測試文件放在和源代碼一樣的目錄下,運行go test會對所有的xxx_test.go進行測試,如下:
[lightdb@lightdb-dev go-web]$ go test
? tool [no test files]
這是一個比較大的主題,可以參考有贊paas的做法,https://cloud.tencent.com/developer/article/1684515,其中還結合了和sonar報告的集成
https://before80.github.io/go_docs_with_hugo/goBlog/2023/CodeCoverageForGoIntegrationTests/
https://go.dev/blog/integration-test-coverage go 1.20在go build上增加了-cover選項,支持集成測試統計
對於集成測試,建議搭建一個專門的平臺維護用例輸出和輸入,自動化迴歸和對比,開發、測試一體化,跟postgresql的make check/make checkworld一樣。
java jacoco是一個可以單元測試和集成測試均覆蓋的覆蓋率工具,支持java agent模式統計。輸出也很完整。
https://blog.csdn.net/d_chunyu/article/details/117136293
6、makefile不僅可用於c/c++,還可以用於go。也就是makefile可用於任何linux下的開發,跟語言無關。尤其是go涉及到部分代碼使用c/c++開發時更是如此。
7、命令行程序設計
go提供了一個設計命令行程序的框架cobra cli(Kubernetes, Docker, Hugo,pgcenter均基於它)
8、go web開發之gin框架
9、go訪問數據庫之postgresql
10、模塊分發
go build可以用來打包整個模塊
go install將其安裝到$GOBIN目錄下
https://stackoverflow.com/questions/59741795/how-to-distribute-a-go-module-with-c-dependencies
11、三方庫
日誌:logrus
kafka:kafka-go ,https://blog.csdn.net/qq_30614345/article/details/131056586,https://zhuanlan.zhihu.com/p/431434480
json:jsoniter
orm:https://github.com/go-gorm/gorm
sql解析:https://github.com/pingcap/parser,當然也可以用postgresql的c語言sql解析器(性能更強),pgpool-ii就是剝離的psotgresql解析器
查看某個模塊依賴的包清單
https://blog.csdn.net/aaqq123456654321/article/details/127113393
go性能分析
pgo,pprof
go與c/c++交互 cgo及環境變量
內存管理
gc
打印堆棧及性能
https://www.51cto.com/article/748837.html