Go語言使用包(package)這種語法元素來組織源碼,所有語法可見性均定義在package這個級別,與Java 、python等語言相比,這算不上什么創新,但與C傳統的include相比,則是顯得“先進”了許多。
myblog
├── conf
│ └── app.conf
├── controllers
│ ├── aboutme_controller.go
│ ├── add_article_controller.go
│ ├── album_controller.go
│ ├── base_controller.go
│ ├── default.go
│ ├── delete_article_controller.go
│ ├── exit_controller.go
│ ├── home_controller.go
│ ├── login_controller.go
│ ├── register_controller.go
│ ├── show_article_controller.go
│ ├── tags_controller.go
│ ├── update_article_controller.go
│ └── upload_controller.go
├── main.go
├── models
│ ├── album_model.go
│ ├── article_model.go
│ ├── home_model.go
│ ├── tags_model.go
│ └── user_model.go
├── myblogweb
├── routers
│ └── router.go
├── static
│ ├── css
│ │ ├── blogsheet.css
│ │ └── lib
│ │ ├── highlight.css
│ │ └── login.css
│ ├── img
│ ├── js
│ │ ├── blog.js
│ │ ├── lib
│ │ │ ├── jquery-3.3.1.min.js
│ │ │ └── jquery.url.js
│ │ └── reload.min.js
│ └── upload
│ └── img
│ └── 2018
│ └── 12
│ └── 11
│ ├── 1544511378-bee2.png
├── tests
│ └── default_test.go
├── utils
│ ├── myUtils.go
│ └── mysqlUtils.go
└── views├── aboultme.html├── album.html├── block│ ├── home_block.html│ └── nav.html├── home.html├── index.tpl├── login.html├── register.html├── show_article.html├── tags.html└── write_article.html
Go 語言的源碼復用建立在包(package)基礎之上。包通過 package, import, GOPATH 操作完成。
1、 main包
Go 語言的入口 main() 函數所在的包(package)叫 main,main 包想要引用別的代碼,需要import導入!
2、 package
src 目錄是以代碼包的形式組織并保存 Go 源碼文件的。每個代碼包都和 src 目錄下的文件夾一一對應。每個子目錄都是一個代碼包。
代碼包包名和文件目錄名,不要求一致。比如文件目錄叫 hello,但是代碼包包名可以聲明為 “main”,但是同一個目錄下的源碼文件第一行聲明的所屬包,必須一致!
同一個目錄下的所有.go文件的第一行添加 包定義,以標記該文件歸屬的包,演示語法:
package 包名
包需要滿足:
- 一個目錄下的同級文件歸屬一個包。也就是說,在同一個包下面的所有文件的package名,都是一樣的。
- 在同一個包下面的文件
package
名都建議設為是該目錄名,但也可以不是。也就是說,包名可以與其目錄不同名。 - 包名為 main 的包為應用程序的入口包,其他包不能使用。
在同一個包下面的文件屬于同一個工程文件,不用import
包,可以直接使用
包可以嵌套定義,對應的就是嵌套目錄,但包名應該與所在的目錄一致,例如:
// 文件:qf/ruby/tool.go中
package ruby
// 可以被導出的函數
func FuncPublic() {
}
// 不可以被導出的函數
func funcPrivate() {
}
包中,通過標識符首字母是否大寫,來確定是否可以被導出。首字母大寫才可以被導出,視為 public 公共的資源。
3、 import
要引用其他包,可以使用 import 關鍵字,可以單個導入或者批量導入,語法演示:
A:通常導入
// 單個導入
import "package"
// 批量導入
import ("package1""package2")
B:點操作我們有時候會看到如下的方式導入包
import(. "fmt"
)
這個點操作的含義就是這個包導入之后在你調用這個包的函數時,你可以省略前綴的包名,也就是前面你調
用的fmt.Println("hello world")
可以省略的寫成Println("hello world")
C:起別名
別名操作顧名思義我們可以把包命名成另一個我們用起來容易記憶的名字。導入時,可以為包定義別名,語法演示:
import (p1 "package1"p2 "package2")
// 使用時:別名操作,調用包函數時前綴變成了我們的前綴
p1.Method()
D:_操作如果僅僅需要導入包時執行初始化操作,并不需要使用包內的其他函數,常量等資源。則可以在導入包時,匿名導入。
這個操作經常是讓很多人費解的一個操作符,請看下面這個import:
import ("database/sql"_ "github.com/ziutek/mymysql/godrv")
_操作其實是引入該包,而不直接使用包里面的函數,而是調用了該包里面的init函數。也就是說,使用下劃線作為包的別名,會僅僅執行init()。
導入的包的路徑名,可以是相對路徑也可以是絕對路徑,推薦使用絕對路徑(起始于工程根目錄)。
4、GOPATH環境變量
import導入時,會從GO的安裝目錄(也就是GOROOT環境變量設置的目錄)和GOPATH環境變量設置的目錄中,檢索 src/package 來導入包。如果不存在,則導入失敗。GOROOT,就是GO內置的包所在的位置。GOPATH,就是我們自己定義的包的位置。
通常我們在開發Go項目時,調試或者編譯構建時,需要設置GOPATH指向我們的項目目錄,目錄中的src目錄中的包就可以被導入了。
5、init() 包初始化
下面我們詳細的來介紹一下這兩個函數:init()、main() 是 go 語言中的保留函數。我們可以在源碼中,定義 init() 函數。此函數會在包被導入時執行,例如如果是在 main 中導入包,包中存在 init(),那么 init() 中的代碼會在 main() 函數執行前執行,用于初始化包所需要的特定資料。例如:包源碼:
src/userPackage/tool.go
?
package userPackage
import "fmt"
func init() {fmt.Println("tool init")
}
主函數源碼:
src/main.go
?
package main
import ("userPackage")
func main() {fmt.Println("main run")// 使用userPackageuserPackage.SomeFunc()
}
執行時,會先輸出 "tool init",再輸出 "main run"。
下面我們詳細的來介紹一下init()、main() 這兩個函數。在 go 語言中的區別如下: 相同點:
兩個函數在定義時不能有任何的參數和返回值。該函數只能由 go 程序自動調用,不可以被引用。
不同點:
init 可以應用于任意包中,且可以重復定義多個。main 函數只能用于 main 包中,且只能定義一個。
兩個函數的執行順序:
在 main 包中的 go 文件默認總是會被執行。
對同一個 go 文件的 init( ) 調用順序是從上到下的。
對同一個 package 中的不同文件,將文件名按字符串進行“從小到大”排序,之后順序調用各文件中的init()函數。
對于不同的 package,如果不相互依賴的話,按照 main 包中 import 的順序調用其包中的 init() 函數。
如果 package 存在依賴,調用順序為最后被依賴的最先被初始化,例如:導入順序 main –> A –> B –> C,則初始化順序為 C –> B –> A –> main,一次執行對應的 init 方法。main 包總是被最后一個初始化,因為它總是依賴別的包
避免出現循環 import,例如:A –> B –> C –> A。
一個包被其它多個包 import,但只能被初始化一次
6、管理外部包
go允許import不同代碼庫的代碼。對于import要導入的外部的包,可以使用 go get 命令取下來放到GOPATH對應的目錄中去。
舉個例子,比如說我們想通過go語言連接mysql數據庫,那么需要先下載mysql的數據包,打開終端并輸入以下命令:
localhost:~ ruby$ go get github.com/go-sql-driver/mysql
安裝之后,就可以在gopath目錄的src下,看到對應的文件包目錄:
也就是說,對于go語言來講,其實并不關心你的代碼是內部還是外部的,總之都在GOPATH里,任何import包的路徑都是從GOPATH開始的;唯一的區別,就是內部依賴的包是開發者自己寫的,外部依賴的包是go get下來的。
擴展
我們可以通過go install 來編譯包文件。
我們知道一個非main包在編譯后會生成一個.a文件(在臨時目錄下生成,除非使用go install安裝到$GOROOT
或?$GOPATH
下,否則你看不到.a),用于后續可執行程序鏈接使用。
比如Go標準庫中的包對應的源碼部分路徑在:$GOROOT/src
,而標準庫中包編譯后的.a文件路徑在$GOROOT/pkg/darwin_amd64
下。
作者:茹姐
出處:千鋒教育go語言教研部