golang 包的管理
以前看golang包管理時,感覺有點混亂,套用python,lua包管理的方式不行,直到今天(2018.10.19)才基本搞清楚golang包管理的意思。
使用包package目的
使用包的目的是為了更加方便的管理原始碼。golang的理念是用資料夾來管理(或者叫約束)同種型別或同種功能的原始碼,例如數學計算的原始碼都放入math資料夾下,系統相關的放入os資料夾下。
一個資料夾下的原始碼中所有包名必須一樣,但是包名可以與檔名不一樣。例如專案中涉及到數學計算,建立一個資料夾為math,為了讓功能獨立,我們每一個功能使用一個go檔案,諸如add.go,sub.go,div.go等。一個go檔案必須要在開頭指定所在的包,語法為package xxx,我們可以寫為package "mymath"。
如何使用包管理
如何使用上面的math模組呢? 如果是在同一個資料夾中(肯定也是在同一個package中),直接呼叫相關函式或全域性變數,而不用加包名限制,加了反而出錯。 如果不是同一個資料夾(注意不在同一個檔案下,不能用一個包名),則首先要import該資料夾,然後使用包名限制來使用函式或者全域性變數,例如mymath.Add()
還有一個問題是,import math資料夾不會包含math資料夾下的子資料夾的原始檔,也就是說如果想要包含資料夾下子檔案,則要import指定到子資料夾名。同時子資料夾中原始碼的package包名也必須不一樣。引用子資料夾中的原始碼時不必帶上父資料夾中的包名,直接用包名即可。
import的本質:
import實際上是按順序解析資料夾中所有的原始檔。當一個原始檔還匯入了其它的包,那麼先將其他的包匯入進來。那麼有三個問題要弄清楚:
- 同一個檔案多次引入的問題。例如,math資料夾下有a,b,c三個檔案,a,b,c又同時import了另外一個資料夾other。那麼當import math時,會多次引入other資料夾下的檔案嗎?答案是不會,一個檔案只會被引入一次。
- 迴圈引用的問題。例如math資料夾下的a檔案原始碼引用了other資料夾,other資料夾中的檔案又引用math。這種情況下該如何處理,迴圈遞迴直至crash嗎?幸好,import機制不允許迴圈引用。所以不必擔心這個問題。
- 解析原始檔時做了什麼? 常量和變數進行初始化,最後執行init函式,如果存在的話(init函式不能主動被呼叫,無論是呼叫自己包中還是其他包中的)。 用一個圖表示上面的過程:
import修飾操作
- 點(.)操作
點(.)操作的含義是:點(.)標識的包匯入後,呼叫該包中函式時可以省略字首包名。點(.)操作的語法為:
import . "package1"
import . "package2"
import . "package3"
...
import (
. "package1"
. "package2"
. "package3"
...
)
下面的示例中,fmt包將使用點操作省略字首包名,os包用法保持不變:
package main
import (
. "fmt"
"os"
)
func main() {
for _, value := range os.Args {
Println(value)
}
}
- 別名操作
別名操作的含義是:將匯入的包命名為另一個容易記憶的別名。別名操作的語法為:
import p1 "package1"
import p2 "package2"
import p3 "package3"
...
import (
p1 "package1"
p2 "package2"
p3 "package3"
...
)
下面的示例中,fmt包將使用別名操作重新命名為f,os包用法保持不變:
package main
import (
f "fmt"
"os"
)
func main() {
for _, value := range os.Args {
f.Println(value)
}
}
- 下劃線(_)操作
下劃線()操作的含義是:匯入該包,但不匯入整個包,而是執行該包中的init函式,因此無法通過包名來呼叫包中的其他函式。使用下劃線()操作往往是為了註冊包裡的引擎,讓外部可以方便地使用。下劃線(_)操作的語法為:
import _ "package1"
import _ "package2"
import _ "package3"
...
import (
_ "package1"
_ "package2"
_ "package3"
...
)
參考: