go 語言的包
Go 語言包的基本概念
目錄Go語言 包的基本概念
Go語言是使用包來組織原始碼的,包(package)是多個 Go 原始碼的集合,是一種高階的程式碼複用方案。Go語言中為我們提供了很多內建包,如 fmt、os、io 等。
包時結構化程式碼的一種方式:每個程式都是由包(通常簡稱為pkg)的概念組成,可以使用自身的包或者從其他包中匯入內容
如同其他一些程式語言中的類庫或者名稱空間的概念,每個Go檔案有且僅屬於一個包。一個包可以由許多以 .go
為副檔名的原始檔組成,因此檔名和包名一般來說都是不同的。
必須在原始檔中非註釋的第一行指明這個檔案屬於與哪個包 package pacakgeName
語句,通過該語句宣告自己所在的包。package main
則表示一個可獨立執行的程勳,每個Go應用程式都包含一個名為main的包。
一個應用程式可以包含不同的包,而且即使只使用main包,也不必包所有的程式碼都寫在一個巨大的檔案裡:可以使用一些較小的檔案,並且在每個檔案非註釋的第一行使用package main
來指明這些檔案檔案都屬於main包。如果打算編譯報名不是main的原始檔,如 pack1,編譯後產生的物件檔案將會是pack1.a
而不是可執行程式。另外,要注意的是所有的包名都應該使用小寫字母
標準庫
標準庫API:https://studygolang.com/pkgdoc
在Go的安裝檔案裡包含了一些可以直接使用的包,即標準庫。在Windows 下,標準庫的位置在Go根目錄下的子目錄pkg\windoes_amd64中;在Linux下,標準庫在Go根目錄的子目錄 pkg\linux_amd64中.
一般情況下,標準包會存放在$GOROOT/pkg/\$GOOS_GOARCH/
目錄下. GO的標準庫包含了大量的包,(如:fmt 和os),但是也可以建立自己的包
如果想要構建一個程式,則包和包內的檔案夠必須以正確的順序進行編譯。包的依賴關係決定了器構建順序。
屬於同一個包的原始檔必須全部一起被編譯
如果對一個包進行更改或者重新編譯,所有引用了這個包的客戶端程式都必須全部重新編譯
Go中的包模型採用了顯示依賴關係的機制來達到快速編譯的目錄。編譯器會從字尾名為.go
的物件檔案(需要且只需要這個檔案)中提取傳遞依賴關係型的資訊
如果A.go 依賴B.go,而B.go 又依賴C.go:
- 編譯C.go,B.go,然後是A.go
- 為了編譯A.go ,編譯器讀取的是B.go,而不是C.go
這種機制對於編譯大型的專案時可以顯著提升編譯速度
示例
在目錄example3 下,有目錄cat 和main 。 在 cat 目錄下有cat.go檔案。 在main目錄下有main.go檔案
//cat.go 檔案
package cat
import "fmt"
var Name string = "Tom"
var Age int = 5
//初始化函式
func init() {
fmt.Println("this is cat package")
fmt.Println("init 函式修改前", Name, Age)
Name = "jack"
Age = 3
fmt.Println("init 函式修改後", Name, Age)
}
//main.go檔案
package main
import (
"dev_code/day9/example3/cat"
"fmt"
)
//呼叫其他包,程式載入順序 cat.go中全域性變數-->cat.go中的init()函式--->main.go中的main()函式
func main() {
fmt.Println("貓的名字:", cat.Name)
fmt.Println("貓的年齡:", cat.Age)
}
//執行main.go檔案 輸出結果:
this is cat package
init 函式修改前 Tom 5
init 函式修改後 jack 3
貓的名字: jack
貓的年齡: 3
程式執行順序
Go程式 的執行(程式啟動)順序如下:
- 按順序匯入所有被main包引用的其他包,然後在每個包中執行如下流程
- 如果該包又匯入了其他包,則從第一部開始遞迴執行,但是每個包只會被匯入一次
- 然後一相反的順序在每個包中初始化常量和變數,如果該包含有init 函式的話,則呼叫該函式。
- 在完成這一切後,main也執行同樣的過程。最後呼叫執行程式
在example5 目錄下有demo包,main包,test包。 在demo包中有demo.go檔案。在main包中有main.go檔案。在test包中有test.go檔案
//demo.go檔案
package demo
import "fmt"
var Name string = "this is demo package "
var Age int = 20
func init() {
fmt.Println("this is demo init()")
fmt.Println("demo.package.Nam:", Name)
fmt.Println("demo.package.Age:", Age)
Name = "this is demo New"
Age = 200
fmt.Println("demo.package.Nam:", Name)
fmt.Println("demo.package.Age:", Age)
}
//test.go檔案
package test
import (
// 在引用的包前面加上 _ 表示只加載這個包,但是不進行引用包裡的函式和變數
_ "dev_code/day9/example4/demo"
"fmt"
)
var Name string = "this is test package"
var Age int = 10
func init() {
fmt.Println("this is test init()")
fmt.Println("test.package.Nam:", Name)
fmt.Println("test.package.Age:", Age)
Name = "this is test New"
Age = 100
fmt.Println("test.package.Nam:", Name)
fmt.Println("test.package.Age:", Age)
}
//main.go檔案
package main
import (
"dev_code/day9/example4/test"
"fmt"
)
func main() {
//main --->test--->demo
fmt.Println("main.package", test.Name)
fmt.Println("main.package", test.Age)
}
//執行main.go檔案輸出結果:
this is demo init()
demo.package.Nam: this is demo package
demo.package.Age: 20
demo.package.Nam: this is demo New
demo.package.Age: 200
this is test init()
test.package.Nam: this is test package
test.package.Age: 10
test.package.Nam: this is test New
test.package.Age: 100
main.package this is test New
main.package 100
匯入包時空白識別符號的作用
如果匯入了一個包,卻沒由使用它,則會在構建時引發錯誤,如imported andnot used
所以,我們可以使用空白識別符號_
來解決
方法一:
宣告一個全域性空白識別符號(在main()函式之前),該識別符號從 未使用的包中訪問符號。
package main
import "os"
var _ = os.Open
func main() {
}
方法二:
在未使用的包前加上一個空白識別符號。只初始化載入該包,而不去使用該包的函式和變數
package main
import _ "os"
func main() {
}
包的別名
在不同的父目錄下,存在相同名字的包。比如,在example4和example5目錄下,都有cat 包。那麼,不管是匯入,還是使用包裡的函式或者變數,都很不方便,容易混淆。
此時我們可以在匯入包的時候,在前面加上包的別名,在使用的使用,使用別名呼叫即可
package main
//匯入fmt 包,同時,設定a 為fmt 包的別名
import a "fmt"
func main() {
//在使用時,使用別名進行呼叫
a.Println("通過包的別名進行呼叫")
}
//輸出結果:
通過包的別名進行呼叫