3.1 Go語言從入門到精通:包

作者:xcbeyond
瘋狂源自夢想,技術(shù)成就輝煌!微信公眾號:《程序猿技術(shù)大咖》號主,專注后端開發(fā)多年,擁有豐富的研發(fā)經(jīng)驗(yàn),樂于技術(shù)輸出、分享,現(xiàn)階段從事微服務(wù)架構(gòu)項(xiàng)目的研發(fā)工作,涉及架構(gòu)設(shè)計(jì)、技術(shù)選型、業(yè)務(wù)研發(fā)等工作。對于Java、微服務(wù)、數(shù)據(jù)庫、Docker有深入了解,并有大量的調(diào)優(yōu)經(jīng)驗(yàn)。 







Go 語言像 Java 語言一樣都擁有包的概念,通過使用包來組織源代碼。包(package)是多個(gè) Go 源碼的集合,是一種高級的代碼復(fù)用方案。Go語言中為我們提供了很多內(nèi)置包,如 fmt、os、io 等。

任何 Go 源代碼文件都必屬于某個(gè)包,同時(shí)源碼文件的第一行有效代碼必須是package pacakgeName 語句,通過該語句聲明自己所在的包。
1、包的概述

Go 語言的包借助了目錄樹的組織形式,一般包的名稱就是其源文件所在目錄的名稱,雖然 Go 語言沒有強(qiáng)制要求包名必須和其所在的目錄名同名,但還是建議包名和所在目錄同名,這樣代碼結(jié)構(gòu)會(huì)更加清晰。
1.1 包的定義

包的聲明如下:

package <package_name>

注意:包聲明必須在 go 源文件的第一行定義。

例如,在 GOPATH/src/a/b/下定義包 c,則在 GOPATH/src/a/b/目錄下的所有 go 源文件第一行需要聲明 package c,而不是聲明為 package a.b.c 或 package a/b/c,但在導(dǎo)入包時(shí),需要帶上路徑 import a/b/c。(注意:這與 Java 語言中包的用法差異很大)
1.2 包的命名規(guī)范

清晰的代碼結(jié)構(gòu),少不了規(guī)范命名,包的命名更為重要。規(guī)范命名的目的是為了讓你的代碼更清晰,別人讀起來更快上手。包命名規(guī)范推薦如下:

包名一般小寫,使用一個(gè)簡短且有意義的單詞或縮寫。
包名與所在包的目錄同名,看目錄知包名。
包名一般采用域名作為包目錄結(jié)構(gòu),以此來確保唯一性。如:GOPATH/src/github.com/xcbeyond/projectName/...。
程序入口包名必須是 main 包。
同一目錄下的所有 go 源文件都屬于同一個(gè)包。

2、包的使用

有了包的存在,必然少不了對其導(dǎo)入,可借助 import 關(guān)鍵字導(dǎo)入想使用的包。具體語法如下:

import “包路徑”

注意:

import 導(dǎo)入語句需放在源碼文件開頭的包聲明語句的下面。
導(dǎo)入的包名需要使用雙引號 "" 括起來。
包名是從 GOPATH/src/ 后開始計(jì)算的,使用 / 進(jìn)行路徑分隔。

通常導(dǎo)入包有單行導(dǎo)入和多行導(dǎo)入兩種方式。

單行導(dǎo)入:

import “包1路徑”
import “包2路徑”

多行導(dǎo)入:

import (
“包1路徑”
“包2路徑”
)

2.1 導(dǎo)入路徑

關(guān)于包的導(dǎo)入路徑有兩種方式,分別是全路徑導(dǎo)入和相對路徑導(dǎo)入。

全路徑導(dǎo)入:

包的絕對路徑就是 GOROOT/src/ 或 GOPATH/src/ 后面包的存放路徑,如下所示:

import “l(fā)ab/test”
import “database/sql/driver”
import “database/sql”

其中:

test 包是自定義的包,其源碼位于 GOPATH/src/lab/test 目錄下。
driver 包的源碼位于 GOROOT/src/database/sql/driver 目錄下。
sql 包的源碼位于 GOROOT/src/database/sql 目錄下。

相對路徑導(dǎo)入:

相對路徑只能用于導(dǎo)入GOPATH 下的包,標(biāo)準(zhǔn)包的導(dǎo)入只能使用全路徑導(dǎo)入。






例如,包 a 的所在路徑是 GOPATH/src/lab/a,包 b 的所在路徑為 GOPATH/src/lab/b,如果在包 b 中導(dǎo)入包 a ,則可以使用相對路徑導(dǎo)入方式。示例如下:

// 相對路徑導(dǎo)入
import “…/a”

2.2 包的引用

包的引用有四種格式,下面以 fmt 包為例分別進(jìn)行說明。

標(biāo)準(zhǔn)引用格式

import "fmt"
    1

用 fmt. 作為前綴來使用 fmt 包中的方法,這是最為常用的一種方式。

示例如下:

package main

import "fmt"

func main() {
    fmt.Println("Hello World!")
}
自定義別名引用格式

在導(dǎo)入包的時(shí)候,我們可以為導(dǎo)入的包設(shè)置別名,簡化使用:

import F "fmt"
    1

其中 F 就是 fmt 包的別名,可以用 F.來代替標(biāo)準(zhǔn)引用格式的 fmt. 來作為前綴使用 fmt 包中的方法。

示例如下:

package main

import F "fmt"

func main() {
    F.Println("Hello World!")
}
   
省略引用格式

import . "fmt"
    1

相當(dāng)于把 fmt 包直接合并到當(dāng)前源文件中,在使用 fmt 包內(nèi)的方法是可以不用加前綴 fmt.而直接引用。

示例如下:

package main

import . "fmt"

func main() {
    Println("Hello World!")
}
   

匿名引用格式

在引用某個(gè)包時(shí),如果只是希望執(zhí)行包初始化的 init 函數(shù),而不使用包內(nèi)部的數(shù)據(jù)時(shí),可以使用匿名引用格式:

import _ "fmt"

使用標(biāo)準(zhǔn)格式引用包,但代碼中卻沒有使用包,編譯器是會(huì)報(bào)錯(cuò)。如果包中有 init 初始化函數(shù),則通過import _ "包的路徑" 這種方式引用包,僅執(zhí)行包的初始化函數(shù),即使包沒有 init 初始化函數(shù),也不會(huì)引發(fā)編譯器報(bào)錯(cuò)。

示例如下:

package main

import (
    _ "database/sql"
    "fmt"
)

func main() {
    Println("Hello World!")
}

2.3 包的初始化

通過前面的學(xué)習(xí)相信大家已經(jīng)大體了解了 Go 程序的啟動(dòng)和加載過程,在執(zhí)行 main 包的 main 函數(shù)之前, Go 引導(dǎo)程序會(huì)先對整個(gè)程序的包進(jìn)行初始化。整個(gè)執(zhí)行的流程如下圖所示:

在這里插入圖片描述

Go語言包的初始化有如下特點(diǎn):

包初始化程序從 main 函數(shù)引用的包開始,逐級查找包的引用,直到找到?jīng)]有引用其他包的包,最終生成一個(gè)包引用的有向無環(huán)圖。
Go 編譯器會(huì)將有向無環(huán)圖轉(zhuǎn)換為一棵樹,然后從樹的葉子節(jié)點(diǎn)開始逐層向上對包進(jìn)行初始化。
單個(gè)包的初始化過程如上圖所示,先初始化常量,然后是全局變量,最后執(zhí)行包的 init 函數(shù)。