access导入链接快还是导入表快_Go 语言设计哲学之十三:理解包导入路径的含义...
Go 語言是使用包(package)作為基本單元來組織源碼的, Go 程序就是這些包鏈接起來而構建的。與C 語言的頭文件包含機制相比則是“先進”了許多。
即便是每次編譯都是從頭開始。避免了 C 語言那種通過頭文件分析依賴的巨大開銷。Go 語言以包為基本構建單元的構建模型,依賴分析非常簡單。
一 構建過程
Go 編譯速度快從三個方面分析:
1.Go 要求每個源文件在開頭處顯式地import所有依賴的包,Go編譯器不必讀取和處理整個文件就可以確定其依賴的包列表;?
2.Go 要求包之間不能存在循環依賴。由于無環,包可以被單獨編譯,也可以并行編譯;?
3.已編譯的 Go 包對應的目標文件(xxx.o 或 xxx.a)中,如下?
??? 1) 該包本身的導出符號信息。
??? 2) 還記錄了其所依賴包的導出符號信息。
這樣,Go編譯器在編譯某包M時,針對M依賴的每個包導入(比如:導入包N),只需讀取一個目標文件即可(比如:N包編譯成的目標文件,該目標文件中已經包含了N包的依賴包的導出信息),而無需再讀取其他文件中的信息了。
通過 package 關鍵字聲明 Go 源文件所屬的包:?
// xx.go package x ... …上述源碼表示:文件 xx.go 是包 x 的一部分。
使用 import 關鍵字導入依賴的標準庫包或第三方包:?
import ( "fmt" // 標準庫包導入 “x/y/z" // 第三方包導入 ) func main() { z.FuncName() fmt.Println("Go!Go!Go!") }看到上面代碼都會想到將import后面的”z”、“fmt”與z.FuncName()和fmt.Println()中的z和fmt認同一個語法元素:包名。 但是以后深入學習Go語言后,發現并非這樣。比如實施分布式消息框架nsq提供的官方client包時,包導入如下:?
import “github.com/nsqio/go-nsq”但是使用導出函數的時候,我們不是go-nsq.FuncName(),而是nsq.FuncName:?
consumer,_:=nsq.NewConsumer("write_order", "ch", config)?
你可能會問最后一個分段到底代表什么?是包名稱?是一個路徑??
Go程序構建過程和其他主流靜態編譯語言一樣,Go語言的程序構建簡單說是由編譯(compile)和鏈接(link)兩個階段。?
一個非main包在編譯后會對應生成一個.a文件,該文件可以理解為是Go包的目標文件(是通過 pack 工具($GOROOT/pkg/tool/darwin_amd64/pack)對.o文件打包后形成的.a).默認情況下在編譯過程中.a文件生成臨時目錄下,除非使用go install安裝到$GOPATH/pkg下(Go1.11版本前),否則你看不到.a文件。如果構建可執行程序,那么.a文件會在構建可執行程序的鏈接階段起使用。
標準庫包的源碼文件在$GOROOT/src 下面,而對應的 .a 文件存放在$GOROOT/pkg/darwin_amd64 下(以 MacOS 上為例;如果是 linux,則是 linux_amd64)
那么構建Go程序時,編譯器會重新編譯依賴包的源文件還是直接鏈接包的.a文件呢?
在使用第三方包的時候,當第三方包源代碼存在且對應的.a已安裝的情況下,編譯器鏈接的仍是根據第三方包最新源代碼編譯出來的.a文件,而不是之前已經安裝到
$GOPATH/pkg/darwin_amd64 下面的目標文件。
那Go 標準庫中的包也是這樣的嗎?
默認情況下對于標準庫中的包,編譯器直接鏈接的是$GOROOT/pkg/darwin_amd64下的.a文件。
二 路徑名?包名?
通過上面的知識,知道了編譯器在編譯過程中必然要使用的是編譯單元(包)所依賴的包的源碼。而編譯器要找到依賴包的源碼文件就需要知道依賴包的源碼路徑。這個路徑由兩部分組成:
? ? 1.基礎搜索路徑
? ? 2.包導入路徑
基礎搜索包是一個全局的設置,下面介紹一下:
所有包(標準庫還是第三方包)的源碼基礎搜索路徑都包括 $GOROOT/src
在上述基礎搜索路徑的基礎上,不同版本的基礎搜索路徑有不同:
1.11 之前
? ? ? ?$GOPATH/src
1.11-1.12?有三種:
? ? ? 經典gopath模式,GO111MODULE=off , $GOPATH/src
? ? ? module-aware 模式,GO111MODULE=on, $GOPATH/pkg/mod
? ? ? auto 模式,GO111MODULE=auto,在$GOPATH/src 路徑下,與 gopath 模式相同;在$GOPATH/src 路徑外且包含 go.mod,與 module-aware 模式相同。
1.13 有兩種
? ? 經典gopath 模式,GO111MODULE=off,$GOPATH/src
? ? module-aware 模式下,GO111MODULE=on/auto,$GOPATH/pkg/mod;?
1.13后?
? ? 只有 module-aware 模式,即只在 module 緩存的目錄下搜索包的源碼。?
搜索路徑第二部分,是位于每個包源碼文件頭部的包導入路徑。基礎搜索路徑與包導入路徑結合在一起,Go編譯器就可以確定一個包的所有依賴包的源碼路徑的集合,這樣集合構成了Go編譯器的源碼搜索路徑空間。?
三 同一源碼的依賴包在同一源碼搜索路徑下包名沖突,怎么辦??
package main import ( "github.com/xxx/p1/pkg/pkg11" “github.com/xxx/p2/pkg/pkg11" ) func main() { pkg1.Func1() }當你有這樣的import的時候,運行main,直接報錯。會告訴你包沖突。如何解決呢?
package mainimport ( p1 "github.com/xxx/p1/pkg/pkg11" p2 “github.com/xxx/p2/pkg/pkg11")func main() { p1.Func1() p2.Func1()}這樣就ok了,解決了問題。
總結
以上是生活随笔為你收集整理的access导入链接快还是导入表快_Go 语言设计哲学之十三:理解包导入路径的含义...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 冬瓜干的功效与作用、禁忌和食用方法
- 下一篇: 华为与西工大合作,面向飞行器的首个流体力