手把手教會你帶你理解Go語言中的包
前言
Hey,大家好呀,我是星期八,咱們原來寫的代碼,都是縮在一塊的,久而久之咱們可能都能感覺到冗余。
所以今天就來學一下包這個東西,將咱們的代碼拆分一下。
包
包可以理解為存放多個.go的文件夾但是這個文件夾下面的第一行的package后面跟的不再是main了而是文件名,就像這樣。
目錄
clac和main.go文件是同級的。
可以看到clac文件夾下的add.go第一行不再是main而是文件夾名 clac同理sub.go第一行也是。
這個只是單獨的解釋包的定義方式沒有實際意義。
包的注意事項
如果這個文件夾要當包使用文件夾名中不能包含_。
導入包
上面我們知道了包是如何定義的。
并且在和main.go同級的項目目錄下建了一個clac包。
在clac包下有倆個文件一個是add.go一個是sub.go兩個文件夾分別都有對應的方法。問題來了???
那我們如何在main.go中使用上述建立的包調用里面的方法呢?
這就是要導入它們了。
示例代碼
- package main
- import (
- "a3_course/clac"
- )
- func main() {
- clac.Add()
- clac.Sub()
- }
執行結果

可以看到在main.go中成功調用了clac包中的代碼。
注:導入包只需要導入到文件夾即可就可以調用下面所有的方法和屬性不再需要包名.xx.go這種方式。
如上述導入calc不管calc下面有幾個.go文件里面的方法和屬性都可以隨便調用。
導入包注意事項
上述我是直接通過
- import (
- "a3_course/clac"
- )
這種方式導入包的但是在你們那可能不太行。
因為我使用的是go mod所以通過項目目錄/包名導入。
如果你沒有使用go mod是傳統的方式那么導入包需要從GOPATH/src進行導入這里不舉例了。
如果還不會使用go mod記得爬樓看以往文章,上面有教程,一篇文章教會你如何使用Go語言Modules,記得要擁抱未來噢。
可見性
可見性在其他語言中有的叫私有成員之類的稱呼在Go中就叫可見性。
Go中可見性很簡單不管是變量還是函數還是結構體。
首字母大寫在哪都能訪問。
首字母小寫只能在當前包使用。
示例
- package clac
- import (
- "fmt"
- )
- //這是一個公開的變量
- var Name = "張三"
- //這是一個私有變量,只能在 clac 包中訪問
- var age = 18
- //這是一個公開的函數
- func Add() {
- fmt.Println("我是做加法的...")
- }
main.go文件
- func main() {
- clac.Add()
- clac.Sub()
- fmt.Println(clac.Name)
- //clac中的age是小寫開頭,屬于私有變量,所以其他包不能訪問
- //fmt.Println(clac.age) // cannot refer to unexported name clac.age
- }
訪問私有變量報錯信息。

結構體可見性的問題
我們知道結構體是有字段的但是你想過結構體的字段大小寫問題嗎?
- type Student struct {
- Name string
- age int
- }
- //age是小寫開頭
結構體名開頭是不是大寫影響的主要是在其他包里面的調用權限問題。
結構體字段開頭是不是大寫主要影響的是調用里面字段的問題一個明顯的問題就是序列化。
更多結構體的相關文章,可前往:Go語言基礎之結構體(春日篇)
示例代碼
- package main
- import (
- "encoding/json"
- "fmt"
- )
- type Student struct {
- Name string
- age int
- }
- func main() {
- var s1 = Student{
- Name: "張三",
- age: 18,
- }
- serializeBytes,err:=json.Marshal(s1)
- if err != nil {
- fmt.Println("序列化失敗")
- }
- serializeStr := string(serializeBytes)
- fmt.Println(serializeStr)
- }
執行結果

會發現執行結果少了一個age。
這是因為age小寫開頭屬于私有變量。
但是json.Marshal(s1)這個已經屬于其他包了所以訪問不到age。
包別名
我們在導入包時其實還可以自定義包名就像Python中的 from xx import xx as yy。
示例代碼
- package main
- //給 clac 包起別名
- import cl "a3_course/clac"
- func main() {
- cl.Add()
- }
執行結果

匿名導入包
匿名導入包就是相當于不用這個包里面的東西。
可能有人就會問了那不用包里面的東西,那還導入作甚呢?
嗯...這個匿名導入包主要要跟包的一個init方法有關系咱們先繼續看。
匿名導入包示例代碼
- package main
- //前面有個 _ 就表示是匿名導入
- import _ "a3_course/clac"
- func main() {
- }
包的init方法
其實每次導入其他包的時候都會執行包的init方法。
示例
- //clac/add.go
- package clac
- import "fmt"
- func init() {
- fmt.Println("clac/add.go/init")
- }
- func Sub() {
- fmt.Println("我是做減法的...")
- }
- //clac/sub.go
- package clac
- import "fmt"
- func init() {
- fmt.Println("clac/sub.go/init")
- }
- func Sub() {
- fmt.Println("我是做減法的...")
- }
main.go
- package main
- import _ "a3_course/clac"
- func main() {
- }
執行結果

可以發現我雖然是匿名導入包但是仍然還是執行了add.go和sub.go下的init方法。
這就說明了一個問題導入一個包會執行這個包下面所有的init方法不管下面有幾個.go文件。
注:包的init方法不能寫參數也不能有返回值init方法只能在導入時調用不能主動調用。
init方法比main方法更提前一步執行。
多個包嵌套導入時init方法執行的順序
代碼較多就直接如圖所示了:

這意思是main.go導入了other包other包導入了inner包 ,套娃。
先看一下執行結果

執行結果是inner的init方法先執行然后是ohter的init方法。
其實本質是碰到import就執行被導入包的init方法。
它的圖應該是這樣子的。

意思是main導入了ohter那就執行other的init方法。
但是在導入ohter時發現other導入了inner那就執行inner的init方法。
總結
上述我們學習了Go基礎之包,學習了如何創建包,組織包,導入包的注意事項。包的權限問題(大寫開頭所有可見),匿名導入包,init方法,多個init方法注意事項。
可能有點不太好理解,但是還是要堅持,一定要多敲兩次。