校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃

主頁 > 知識庫 > Golang import本地包和導入問題相關詳解

Golang import本地包和導入問題相關詳解

熱門標簽:智能電銷機器人營銷 賺地圖標注的錢犯法嗎 福州鐵通自動外呼系統 長沙ai機器人電銷 廣東語音外呼系統供應商 烏魯木齊人工電銷機器人系統 地圖標注測試 澳門防封電銷卡 濮陽自動外呼系統代理

1 本地包聲明

包是Go程序的基本單位,所以每個Go程序源代碼的開始都是一個包聲明:

package pkgName

這就是包聲明,pkgName 告訴編譯器,當前文件屬于哪個包。一個包可以對應多個*.go源文件,標記它們屬于同一包的唯一依據就是這個package聲明,也就是說:無論多少個源文件,只要它們開頭的package包相同,那么它們就屬于同一個包,在編譯后就只會生成一個.a文件,并且存放在$GOPATH/pkg文件夾下。

示例:

(1) 我們在$GOPATH/目錄下,創建如下結構的文件夾和文件:

分別寫入如下的代碼:

hello.go

//hello.go
package hello

import (
  "fmt"
)

func SayHello() {
  fmt.Println("SayHello()-->Hello")
}

hello2.go

//hello2.go
package hello

import (
  "fmt"
)

func SayWorld() {
  fmt.Println("SayWorld()-->World")
}

main.go

//main.go
package main

import (
  "hello"
)

func main() {
  hello.SayHello()
  hello.SayWorld()
}

分析:

根據hello.go/hello2.go中的package聲明可知,它們倆屬于同一個包–hello,那么根據分析,編譯后只會生成一個*.a文件。

執行命令:

go install hello

該命令的意思大概是:編譯并安裝hello包,這里安裝的意思是將生成的*.a文件放到工作目錄$GOPATH/pkg目錄下去

運行后:

從結果看出,果然只生成了一個包,并且名為hello.a

那么我們提出第二個問題:生成的*.a文件名是否就是我們定義的包名+.a后綴?

為了驗證這個問題,我們對源碼做一些更改:
將hello.go/hello2.go中的package聲明改為如下:

package hello_a

在編譯安裝包之前,先清除上一次生成的包:

go clean -i hello

再次編譯安裝該包:

go install hello_a

按照“正常推理”,上面這句命令是沒什么問題的,因為我們已經將包名改成hello_a了啊,但是實際的運行結果是這樣的:

oh~No!!
那么,我們再試試用這條命令:

go install hello

臥槽!!居然成功了!!是不是??

那么我們嘗試生成一下可執行程序,看看能不能正常運行呢?

go build main

又報錯了!!!

看這報錯提示,好像應該改一下main.go源碼,那就改成如下吧:

//main.go
package main

import (
  "hello_a"
)

func main() {
  hello_a.SayHello()
  hello_a.SayWorld()
}

改成上面這樣也合情合理哈?畢竟我們把包名定義成了hello_a了!
那就再來編譯一次吧:

go build main

繼續報錯!

等等!!有新的發現,對比上兩次的報錯信息,可見第一次還能能找到hello_a包的,更改源碼后居然還TM找不到hello_a包了??
好吧,那咱再改回去,不過這回只改包的導入語句,改成:

import (
  "hello"
)

再次編譯:

go build main

臥槽!!居然沒報錯了!!再運行一下可執行程序:

好吧,終于得到了想要的結果!

那進行到這里能說明什么呢?

(1) 一個包確實可以由多個源文件組成,只要它們開頭的包聲明一樣
(2)一個包對應生成一個*.a文件,生成的文件名并不是包名+.a
(3) go install ××× 這里對應的并不是包名,而是路徑名!!
(4) import ××× 這里使用的也不是包名,也是路徑名!
(5) ×××××.SayHello() 這里使用的才是包名!

那么問題又來了,我們該如何理解(3)、(4)中的路徑名呢?
我覺得,可以這樣理解:
這里指定的是該×××路徑名就代表了此目錄下唯一的包,編譯器連接器默認就會去生成或者使用它,而不需要我們手動指明!

好吧,問題又來了,如果一個目錄下有多個包可以嗎?如果可以,那該怎么編譯和使用??

那我們繼續改改源代碼:

首先,保持hello2.go 不變,改動hello.go為如下代碼:

//hello.go
package hello

import (
  "fmt"
)

func SayHello() {
  fmt.Println("SayHello()-->Hello")
}

并且更改main.go的源碼如下

//main.go
package main

import (
  "hello"
)

func main() {
  hello.SayHello()
  hello_a.SayWorld()
}

再次清理掉上次生成的可執行程序與包:

go clean -i hello
go clean -x main

你可以試著執行如上的命令,如果不能清除,那就手動刪除吧!
反正,還原成如下樣子:

那么再次嘗試編譯并安裝包,不過注意了,此時hello目錄下有兩個包了,不管是否正確,我們先嘗試一下:

go install hello

oh~~果然出錯了!!

 
看到了嗎?它說它找到了兩個包了啊!!!

那這能說明什么呢??

其實這就更加確定的說明了,我們上面的推測是正確的!

(3) go install ××× 這里對應的并不是包名,而是路徑名!!

這里指定的是該×××路徑名就代表了此目錄下唯一的包,編譯器連接器默認就會去生成或者使用它,而不需要我們手動指明!

好吧,證明了這個還是挺興奮的!!那我們繼續!!

如果一個目錄下,真的有兩個或者更多個包,那該如何生成??
抱著試一試的態度,我嘗試了許多可能,但無一正確,最后一個命令的結果是讓我崩潰的:

go help install

恩!對!你沒有看錯:installs the packages named by the import paths
What the fuck!! 以后還是決定要先看文檔再自己做測試!!

好吧,綜上所述,一個目錄下就只能有一個包吧,因為都是指定路徑,沒有辦法指定路徑下的某個具體的包,這樣的做法其實也挺好,讓源代碼結構更清晰!

2 包的導入問題

導入包:

  • 標準包使用的是給定的短路徑,如"fmt"、"net/http"
  • 自己的包,需要在工作目錄(GOPATH)下指定一個目錄,improt 導入包,實際上就是基于工作目錄的文件夾目錄

導入包的多種方式:

  • 直接根據$GOPATH/src目錄導入import "test/lib"(路徑其實是$GOPATH/src/test/lib)
  • 別名導入:import alias_name "test/lib" ,這樣使用的時候,可以直接使用別名
  • 使用點號導入:import . "test/lib",作用是使用的時候直接省略包名
  • 使用下劃線導入:improt _ "test/lib",該操作其實只是引入該包。當導入一個包時,它所有的init()函數就會被執行,但有些時候并非真的需要使用這些包,僅僅是希望它的init()函數被執行而已。這個時候就可以使用_操作引用該包。即使用_操作引用包是無法通過包名來調用包中的導出函數,而是只是為了簡單的調用其init函數()。往往這些init函數里面是注冊自己包里面的引擎,讓外部可以方便的使用,例如實現database/sql的包,在init函數里面都是調用了sql.Register(name string, driver driver.Driver)注冊自己,然后外部就可以使用了。
  • 相對路徑導入     import   "./model"  //當前文件同一目錄的model目錄,但是不建議這種方式import

首先,還是對上面的示例程序做一個更改,這次我們讓它變得更加簡單點,因為接下來討論的東西,可能會稍微有點繞~~

首先,刪除hello2.go,清理掉編譯生成的文件,其他文件內容如下:

hello.go

//hello.go
package hello

import (
  "fmt"
)

func SayHello() {
  fmt.Println("SayHello()-->Hello")
}

main.go

//main.go
package main

import (
  "hello"
)

func main() {
  hello.SayHello()
}

最后,讓整體保持如下的樣式:

我們先編譯一次,讓程序能夠運行起來:

go install hello
go build main
./main

好吧,假如你能看到輸出,那就沒問題了!
此時,再來看看整體的結構:

按照C/C++的方式來說,此時生成了hello.a這個鏈接庫,那么源文件那些應該就沒有必要了吧,所以。。。。我們這樣搞一下,我們來更改一下hello.go源碼,但不編譯它!
hello.go

//hello.go
package hello

import (
  "fmt"
)

func SayHello() {
  fmt.Println("SayHello()-->Hello_modifi...")
}

然后,我們刪除之前的可執行文件main,再重新生成它:

rm main
go build main

恩~~等等,我看一下運行結果:

What the fuck!!!為什么出來的是這貨???

好吧,為了一探究竟,我們再次刪除main文件,并再次重新編譯,不過命令上得做點手腳,我們要看看編譯器連接器這兩個小婊砸到底都干了些什么,為啥是隔壁老王的兒子出來了??!!

rm main
go build -x -v main

結果:

那么我們一步一步對這個結果做一個分析:

#首先,它好像指定了一個臨時工作目錄
WORK=/tmp/go-build658882358 

#看著樣子,它好像是要準備編譯hello目錄下的包
hello
#然后創建了一系列臨時文件夾
mkdir -p $WORK/hello/_obj/  
mkdir -p $WORK/

#進入包的源文件目錄
cd /home/yuxuan/GoProjects/import/src/hello 

#調用6g這個編譯器編譯生成hello.a,存放在$WORK/臨時目錄下
/opt/go/pkg/tool/linux_amd64/6g -o $WORK/hello.a -trimpath $WORK -p hello -complete -D _/home/yuxuan/GoProjects/import/src/hello -I $WORK -pack ./hello.go

#要編譯main目錄下的包了
main
#還是創建一系列的臨時文件夾
mkdir -p $WORK/main/_obj/  
mkdir -p $WORK/main/_obj/exe/

#進入main文件夾
cd /home/yuxuan/GoProjects/import/src/main

#調用6g編譯器,編譯生成main.a,存放于$WORK/臨時目錄下
/opt/go/pkg/tool/linux_amd64/6g -o $WORK/main.a -trimpath $WORK -p main -complete -D _/home/yuxuan/GoProjects/import/src/main -I $WORK -I /home/yuxuan/GoProjects/import/pkg/linux_amd64 -pack ./main.go

#最后它進入了一個“當前目錄”,應該就是我們執行go build命令的目錄
cd .

#調用連接器6l 然后它鏈接生成a.out,存放與臨時目錄下的$WORK/main/_obj/exe/文件夾中,但是在鏈接選項中并未直接發現hello.a
#從鏈接選項:-L $WORK -L /home/yuxuan/GoProjects/import/pkg/linux_amd64中可以看出,連接器首先搜索了$WORK臨時目錄下的所有*.a文件,然后再去搜索/home/yuxuan/GoProjects/import/pkg/linux_amd64目錄下的*.a文件,可見原因
/opt/go/pkg/tool/linux_amd64/6l -o $WORK/main/_obj/exe/a.out -L $WORK -L /home/yuxuan/GoProjects/import/pkg/linux_amd64 -extld=gcc $WORK/main.a

#最后,移動可執行文件并重命名
mv $WORK/main/_obj/exe/a.out main

到這里,其實差不多也就得出結論了,連接器在連接時,其實使用的并不是我們工作目錄下的hello.a文件,而是以該最新源碼編譯出的臨時文件夾中的hello.a文件。

當然,如果你對這個結論有所懷疑,可以試試手動執行上述命令,在最后鏈接時,去掉-L $WORK的選項,再看看運行結果!

那么,這是對于有源代碼的第三方庫,如果沒有源代碼呢?

其實,結果顯而易見,沒有源代碼,上面的臨時編譯不可能成功,那么臨時目錄下就不可能有.a文件,所以最后鏈接時就只能鏈接到工作目錄下的.a文件!

但是,如果是自帶的Go標準庫呢?

其實也可以用上述的方法驗證一下,驗證過程就不寫了吧?
最后得到的結果是:對于標準庫,即便是修改了源代碼,只要不重新編譯Go源碼,那么鏈接時使用的就還是已經編譯好的*.a文件!

3 導入包的三種模式

包導入有三種模式:正常模式、別名模式、簡便模式

Go language specification中關于import package時列舉的一個例子如下:

Import declaration Local name of Sin

import “lib/math” math.Sin 
import m “lib/math” m.Sin 
import . “lib/math” Sin

我們看到import m “lib/math” m.Sin一行,在上面的結論中說過lib/math是路徑,import語句用m替代lib/math,并在代碼中通過m訪問math包中導出的函數Sin。
那m到底是包名還是路徑呢?
答案顯而易見,能通過m訪問Sin,那m肯定是包名了!
那問題又來了,import m “lib/math”該如何理解呢?

根據上面得出的結論,我們嘗試這樣理解m:m指代的是lib/math路徑下唯一的那個包!

4 總結

經過上面這一長篇大論,是時候該總結一下成果了:

多個源文件可同屬于一個包,只要聲明時package指定的包名一樣;一個包對應生成一個*.a文件,生成的文件名并不是包名+.a組成,應該是目錄名+.a組成go install ××× 這里對應的并不是包名,而是路徑名!!import ××× 這里使用的也不是包名,也是路徑名×××××.SayHello() 這里使用的才是包名!指定×××路徑名就代表了此目錄下唯一的包,編譯器連接器默認就會去生成或者使用它,而不需要我們手動指明!一個目錄下就只能有一個包存在對于調用有源碼的第三方包,連接器在連接時,其實使用的并不是我們工作目錄下的.a文件,而是以該最新源碼編譯出的臨時文件夾中的.a文件對于調用沒有源碼的第三方包,上面的臨時編譯不可能成功,那么臨時目錄下就不可能有.a文件,所以最后鏈接時就只能鏈接到工作目錄下的.a文件對于標準庫,即便是修改了源代碼,只要不重新編譯Go源碼,那么鏈接時使用的就還是已經編譯好的*.a文件包導入有三種模式:正常模式、別名模式、簡便模式

到此這篇關于Golang import本地包和導入問題相關詳解的文章就介紹到這了,更多相關Golang import包內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • 解決Goland 提示 Unresolved reference 錯誤的問題
  • go語言入門環境搭建及GoLand安裝教程詳解
  • 淺談goland導入自定義包時出錯(一招解決問題)

標簽:阿克蘇 廣西 慶陽 西雙版納 德州 調研邀請 太原 貴陽

巨人網絡通訊聲明:本文標題《Golang import本地包和導入問題相關詳解》,本文關鍵詞  Golang,import,本地,包,和,導入,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《Golang import本地包和導入問題相關詳解》相關的同類信息!
  • 本頁收集關于Golang import本地包和導入問題相關詳解的相關信息資訊供網民參考!
  • 推薦文章
    校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃
    色琪琪一区二区三区亚洲区| 成人国产亚洲欧美成人综合网| 亚洲视频在线一区二区| 国产亚洲一区二区三区四区| 久久青草欧美一区二区三区| 欧美精品一区二区在线观看| 精品99一区二区三区| 欧美tickling网站挠脚心| 9191久久久久久久久久久| 欧美乱妇15p| 日韩一区二区麻豆国产| 久久综合成人精品亚洲另类欧美| 欧美电影免费观看高清完整版在线 | 国产精品福利电影一区二区三区四区| 国产拍欧美日韩视频二区| 日本一区二区三区四区| 一区精品在线播放| 亚洲国产一区二区三区| 美腿丝袜亚洲三区| 成人三级伦理片| 欧洲视频一区二区| 日韩午夜激情视频| 国产欧美一区二区在线观看| 一区二区在线看| 日本成人在线看| 成人黄色一级视频| 欧美日韩一区视频| 久久影院视频免费| 亚洲免费在线观看| 久久66热re国产| 91玉足脚交白嫩脚丫在线播放| 制服丝袜成人动漫| 中文字幕一区日韩精品欧美| 无吗不卡中文字幕| 国产91色综合久久免费分享| 色天使久久综合网天天| 精品成人一区二区三区四区| 亚洲欧美aⅴ...| 精品亚洲欧美一区| 欧美午夜影院一区| 国产欧美日韩综合| 毛片一区二区三区| 欧洲中文字幕精品| 欧美激情中文不卡| 日韩成人一级大片| 99久久久久免费精品国产 | 91视频免费观看| 精品久久一区二区三区| 一区二区三区欧美日| 成人短视频下载| 精品日韩欧美在线| 天天免费综合色| 色噜噜狠狠色综合中国| 欧美—级在线免费片| 国产一区二区三区精品视频 | 麻豆精品视频在线| 欧美日韩国产精品成人| 亚洲一区在线观看视频| 91在线视频播放| 国产精品不卡在线| 国产99久久久精品| 日韩精品一区二区三区中文不卡| 亚洲一区免费视频| 欧美色倩网站大全免费| 亚洲综合久久av| 91福利在线导航| 亚洲欧美一区二区三区久本道91| 国产黄色精品网站| 久久免费的精品国产v∧| 久久99精品久久只有精品| 欧美日本乱大交xxxxx| 亚洲国产日韩精品| 欧美吞精做爰啪啪高潮| 一区二区三区资源| 欧美中文字幕一区二区三区亚洲| 最新国产精品久久精品| 99这里只有精品| 成人欧美一区二区三区1314| 91在线观看一区二区| 亚洲精品国产无套在线观| 欧美性做爰猛烈叫床潮| 亚洲电影一级黄| 欧美日韩成人综合在线一区二区| 天堂蜜桃一区二区三区| 欧美一级欧美三级在线观看| 美女视频免费一区| 久久久另类综合| 99久久久无码国产精品| 亚洲最新视频在线观看| 欧美日韩高清在线| 理论电影国产精品| 国产精品色哟哟| 欧美午夜电影网| 日日夜夜精品免费视频| 久久婷婷国产综合精品青草| 波多野洁衣一区| 亚洲综合男人的天堂| 日韩欧美国产1| 97久久精品人人做人人爽| 亚洲成人av免费| 中文字幕欧美激情一区| 欧美日韩不卡一区二区| 国产91精品一区二区麻豆网站 | 亚洲一级二级三级在线免费观看| 宅男噜噜噜66一区二区66| 国产另类ts人妖一区二区| 亚洲人吸女人奶水| 日韩一卡二卡三卡四卡| 播五月开心婷婷综合| 午夜a成v人精品| 国产精品久久久久久久久免费桃花| 欧美色综合影院| 国产福利精品导航| 丝袜亚洲另类丝袜在线| 欧美国产精品v| 91精品国产91综合久久蜜臀| 91在线云播放| 国产精品一区二区91| 日日夜夜一区二区| 亚洲日穴在线视频| 久久嫩草精品久久久久| 在线电影院国产精品| 91网址在线看| 国产成人免费在线观看不卡| 丝袜美腿成人在线| 亚洲精品视频在线看| 欧美国产日韩在线观看| 欧美电影免费观看高清完整版在| 在线视频中文字幕一区二区| www.亚洲色图.com| 国产精品一区二区黑丝 | 日韩亚洲欧美在线观看| 91丝袜高跟美女视频| 国产一区二区免费在线| 蜜桃一区二区三区在线观看| 一区二区三区产品免费精品久久75| 国产日韩欧美麻豆| 精品国产一区二区三区四区四| 欧美日韩免费在线视频| 一本到一区二区三区| 成人性视频免费网站| 韩国v欧美v日本v亚洲v| 美国十次综合导航| 日韩高清在线不卡| 亚洲高清免费在线| 五月婷婷综合网| 亚洲成人精品在线观看| 亚洲一区二区在线播放相泽| 亚洲色图自拍偷拍美腿丝袜制服诱惑麻豆| 久久丝袜美腿综合| 久久免费国产精品| 中文av一区特黄| 国产精品久久久久久久蜜臀| 国产精品久久久久一区| 亚洲图片你懂的| 亚洲女同一区二区| 亚洲欧美日本韩国| 亚洲五码中文字幕| 丝瓜av网站精品一区二区| 青娱乐精品视频| 九九久久精品视频| 国产激情偷乱视频一区二区三区| 国产乱人伦偷精品视频免下载| 国产尤物一区二区在线 | 亚洲欧美色综合| 亚洲第一福利一区| 精品一区二区三区免费观看| 国产高清视频一区| 91蜜桃免费观看视频| 欧美中文字幕一区二区三区| 欧美精品99久久久**| 2021国产精品久久精品| 亚洲国产精品成人综合 | 中文字幕不卡的av| 一区二区三区四区乱视频| 日韩成人dvd| 国产精品 日产精品 欧美精品| 91网站最新地址| 欧美亚洲自拍偷拍| 亚洲精品在线观看视频| 国产精品电影院| 日日摸夜夜添夜夜添精品视频 | 久久久影视传媒| 亚洲欧洲成人自拍| 婷婷久久综合九色综合伊人色| 久久99精品久久久久婷婷| aaa欧美日韩| 精品国产精品网麻豆系列| 亚洲男人天堂av网| 美国欧美日韩国产在线播放| 91在线视频播放地址| 精品少妇一区二区三区视频免付费 | 一区二区三区四区不卡在线 | 日韩欧美精品三级| 亚洲欧美激情插 | 色av成人天堂桃色av| 欧美一级二级三级乱码| 国产精品久久久久婷婷| 免费在线观看一区二区三区| 99久精品国产|