go語言中包的使用
在golang中,所有原始檔都屬於一個包,golang的包具有以下特性:
- 包可以被其他包引用
- 每個golang程式只有一個main包
- 包的主要用途是提高程式碼的可複用性
本節,我們將介紹包的相關概念以及使用方法,如果你還沒有閱讀過前面的文章,可以通過以下連結進行閱讀
一. GOPATH 環境變數
1. 什麼是GOPATH?
golang包的使用依賴一個重要的環境變數:GOPATH
,無論是自己的程式碼還是第三方程式碼,都以GOPATH
作為工作目錄和一套完整的工程目錄規則。GOPATH目錄約定有三個子目錄,主要用於
- src:存放各種包原始碼,src裡的一個目錄就是一個包
- pkg:存放編譯原始碼後的類庫
- bin:存放編譯原始碼後的可執行程式
GOPATH
允許多個目錄,設定多個目錄時,需要使用環境變數分隔符來區分。Unix/Linux的環境變數分隔符是英文輸入法下的冒號(:),windows的環境變數分隔符是英文分號(;)。
使用GOPATH
時,golang會在以下目錄中搜索包:
-
- GOROOT/src:該目錄儲存了Go標準庫裡程式碼。
-
- GOPATH/src:該目錄儲存了應用自身的程式碼和第三方依賴的程式碼。
2. 設定GOPATH環境變數
在Unix/Linux中,使用sudo vim /etc/profile
開啟系統profile檔案,並追加以下內容設定GOPATH
GO111MODULE
為關閉狀態,GO111MODULE
環境變數我們在文章中後面部分說明
export GOPATH=/Users/pan/go # 把自己的golang專案目錄作為GOPATH的變數
export GO111MODULE=off # 關閉golang 11.1 版本以後的模組功能
使用source /etc/profile
命令重新載入環境變數
3. 包的使用
(1)main包與包的引入
a. 引入系統包
我們可以通過package
關鍵字定義一個包,使用import
引入其他包,如果需要引入多個包,可以將各個包宣告在括號內
package main import ( // 引入系統的包 "fmt" ) func main() { // 呼叫系統包的函式 fmt.Println("Hello World") }
在以上程式碼中,我們通過main
關鍵字定義了main包,主函式main必須位於main包下。程式中引入了fmt
包,該包由golang本身提供。
b. 引入自定義包
我們在GOPATH/src目錄下建立兩個檔案:
檔案1,庫檔案位於jkdev.cn/test/mypkg/lib.go
,新增以下程式碼
package mypkg
import "fmt"
func TestFunc() {
fmt.Println("call testFunc")
}
檔案2,主檔案jkdev.cn/test/main.go
,新增以下程式碼
package main
// 引入自定義包
import "jkdev.cn/test/mypkg"
func main() {
// 呼叫自定義包的函式
mypkg.TestFunc()
}
自定義的包由我們自己定義,但要注意的是,一個目錄對應一個包,同時,包名應當和目錄名一致。引入包時,路徑相對應GOPATH/src,我們可以根據自己的程式的功能模組劃分不同的包。
(2)包的作用域
-
包內:在同一個包內定義的函式、變數、常量、結構體,可以被包內的所有其他程式碼任意訪問,它們屬於包內公開。
-
包外:如果函式、變數、常量、結構體位於不同的包下,如果將它們的首字母使用大寫標識,表示它們是公開訪問的。對於結構體欄位。如果想要在包外進行訪問,還要讓結構體欄位變數名使用首字母大寫。
二. 編譯
golang中go build
命令主要用於編譯程式碼。在包的編譯過程中,若有必要,會同時編譯與之相關聯的包。
假設我們的設定GOPATH是/Users/pan/go
,我們在GOPATH之下的src建立建立程式碼test目錄,並新增lib.go
和main.go
兩個檔案:
此時,原始檔相對於GOPATH的路徑如下。接下來我們對這兩個go原始檔進行編譯
go GOPATH目錄
├─src 原始碼目錄
│ ├─test 專案目錄
│ ├─lib.go 公共函式檔案
│ └─main.go 主函式檔案
lib.go 程式碼如下:
package main
import "fmt"
func testFunc() {
fmt.Println("call testFunc")
}
main.go程式碼如下:
package main
func main() {
testFunc()
}
示例中的兩個原始檔都屬於
main
包,所以在main.go檔案中能正常引入lib.go
檔案。
1. go build
無引數編譯不依賴GOPATH
,需要在原始碼目錄下進行編譯
# 進入原始碼目錄
cd ~/go/src/test
# 編譯程式碼
go build
我們還可以-o
指定編譯後輸出的可執行檔案的檔名,如下
go build -o main
2. go build 檔案列表
使用“go build+檔案列表”編譯時,檔案列表中的每個檔案必須是同一個包的 Go 原始碼
# 進入原始碼目錄
cd ~/go/src/test
# 編譯
go build lib.go main.go
3. go build 包
包的路徑相對於GOPATH
,“go build+包”編譯時,原始檔需要存放在GOPATH/src
下的路徑,但是我們可以在任意有讀寫許可權的目錄執行編譯命令,如下
# test 相對於GOPATH/src
go build test
4. go install
與go build
具有相似功能的是go install
命令,go install
用來生成庫和工具並存放於GOPATH中。一是編譯包檔案(無main包),將編譯後的包檔案放到 pkg 目錄下(GOPATH/pkg)。二是編譯生成可執行檔案(有main包),將可執行檔案放到 bin 目錄(GOPATH/bin)。
5. go build 和 go install 對比
- 相同點:都能生成可執行檔案
- 不同點:go build 不能生成包檔案, go install 可以生成包檔案;go build 生成可執行檔案在當前目錄下, go install 生成可執行檔案在bin目錄下($GOPATH/bin)。
三、 Go模組
golang在1.11版本引入和Go Modules,我們還可以叫做Go模組,模組依賴於上文提到的GO111MODULE
環境變數。它是golang官方提供的包管理工具,通過Go Modules,我們可以不必將專案放在GOPATH上。
1. GO111MODULE環境變數
用環境變數GO111MODULE設定開啟或者關閉模組支援,它有三個可選值:off、on、auto,預設是auto。
GO111MODULE=off
:無模組支援,go會從GOPATH尋找包。GO111MODULE=on
:模組支援,根據go.mod
檔案下載依賴GO111MODULE=auto
:在$GOPATH/src外面且專案根目錄有go.mod
檔案時,自動開啟模組支援
在使用模組的時候,GOPATH是無意義的,但golang還是會把下載的依賴儲存於GOPATH之下。
2. 使用go模組
使用Go Modules時,我們先將GO111MODULE
設定為on或者auto,Go Modules和GOPATH不同,不需要包含固定的三個字目錄。一個空的原始碼目錄,只要初始化好go.mod
檔案,就可以定義一個Module。我們可以使用以下命令建立一個新的Module
# 建立一個空的工作目錄
mkdir -p ~/Work/go/test
# 進入工作目錄
cd ~/Work/go/test
# 初始化一個module
go mod init testmodule
我們可以看到自動生成的go.mod
檔案的內容如下
module testmodule
go 1.16
(1)下載依賴
Go Modules會為我們進行包管理,並自動更新go.mod檔案,如果需要引入新的依賴,我們只需要在終端執行go get 包名
即可引入第三方包,如
go get github.com/satori/go.uuid
執行命令後,Go Modules會從我們在安裝golang時設定的GOPROXY
映象倉庫地址去下載對應的包,安裝完成之後我們看到go.mod
已經發生變化,如下
module testmodule
go 1.16
require github.com/satori/go.uuid v1.2.0 // indirect
我們也可以先編輯好go.mod
檔案,然後在終端使用go mod download
,golang會自動幫我們下載依賴包到本地。如果我們需要引入多個包,將所有包名解除安裝括號內,如下程式碼
module testmodule
go 1.16
require (
github.com/satori/go.uuid v1.2.0 // indirect
gorm.io/gorm v1.21.11 // indirect
)
(2)更新依賴關係
使用go mod tidy
更新依賴關係,該命令拉取缺少的模組,移除不用的模組。Go Modules可以輕易地進行一個包的依賴管理和版本控制,go build
和go install
將自動使用go.mod中的依賴關係,減少了GOPATH管理時的複雜性。
本文介紹了Go的包的基本管理方法,後面,我們會循序漸進地介紹golang的基礎知識。如果喜歡,歡迎訂閱!