理解Go語言中“包”匯入
我們在使用其他語言,比如Java,是有包的概念的,它是Java語言中組織我們的Java檔案的一個概念,比如java.lang這個包,他裡面有很多我們常用的類,比如String。在Go語言中,包也是類似的概念,它是把我們的go檔案組織起來,可以方便進行歸類、複用等目的。 比如Go內建的net包
net
├── http
├── internal
├── rpc
├── smtp
├── testdata
├── textproto
└── url
以上是net包的一個目錄結構,net本身是一個包,net目錄下的http又是一個包。從這個大家可以看到,go語言的包其實就是我們計算機裡的目錄,或者叫資料夾,通過它們進行目錄結構和檔案組織,go只是對目錄名字做了一個翻譯,叫【包】而已。比如這裡的net包其實就是net目錄,http包其實就是http目錄,這也是go語言中的一個命名習慣,包名和檔案所在的目錄名是一樣的。
go語言中包的定義和使用看起來十分簡單:
通過package關鍵字定義包:
package xxx
使用import關鍵字,匯入要使用的標準庫包或第三方依賴包。
import "fmt"
fmt.Println("Hello, World")
通過上面的程式碼,我們大致對包有了一點了解。我們來看一個另一段程式碼。
import "a/b/c"
c.Func1()
很多Golang初學者看到上面程式碼,都會想當然的將import後面的"c"、"fmt"當成包名,將其與c.Func1()和 fmt.Println()中的c和fmt認作為同一個語法元素:包名。但在深入Golang後,很多人便會發現事實上並非如此。不禁有個疑問:import後面路徑中的最後一個元素到底代表的是啥? 是包名還是僅僅是一個路徑?
本次實驗目錄結構:

我們建立libproj2/foo目錄,其中的foo1.go程式碼如下:
//foo1.go
package bar
import "fmt"
func Bar1() {
fmt.Println("Bar1")
}
注意:這裡package名為bar,與目錄名foo完全不同。
接下來就給app2帶來了難題:該如何import bar包呢?
我們假設import路徑中的最後一個元素是包名,而非路徑名。
//app2/main.go
package main
import (
"libproj2/bar"
)
func main() {
bar.Bar1()
}
編譯app2:
$go build -x -v app2
WORK=/var/folders/2h/xr2tmnxx6qxc4w4w13m01fsh0000gn/T/go-build736904327
main.go:5:2: cannot find package "libproj2/bar" in any of:
/Users/tony/.Bin/go14/src/libproj2/bar (from $GOROOT)
/Users/tony/Test/Go/pkgtest/src/libproj2/bar (from $GOPATH)
編譯失敗,在兩個路徑下無法找到對應libproj2/bar包。
我們的假設錯了,我們把它改為路徑:
//app2/main.go
package main
import (
"libproj2/foo"
)
func main() {
bar.Bar1()
}
再編譯執行:
$go build app2 $app2 Bar1
這回編譯順利通過,執行結果也是OK的。這樣我們得到了結論: (3)import後面的最後一個元素應該是路徑,就是目錄,並非包名 。
go編譯器在這些路徑(libproj2/foo)下找bar包。這樣看來,go語言的慣例只是一個特例,即恰好目錄名與包名一致罷了。也就是說下面例子中的兩個foo含義不同:
import "libproj1/foo"
func main() {
foo.Foo()
}
import中的 foo 只是一個檔案系統的路徑罷了。而下面foo.Foo()中的 foo 則是包名。而這個包是在libproj1/foo目錄下的原始碼中找到的。