婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > 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~~果然出錯了??!

 
看到了嗎?它說它找到了兩個包了?。。。?/p>

那這能說明什么呢??

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

(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 ××× 這里對應的并不是包名,而是路徑名?。mport ××× 這里使用的也不是包名,也是路徑名×××××.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本地包和導入問題相關詳解的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    亚洲国产日韩一级| 日韩国产欧美三级| 欧美日韩在线观看一区二区| 亚洲国产欧美在线| 亚洲线精品一区二区三区| 亚洲欧美在线aaa| 久久久亚洲精品一区二区三区| 懂色av一区二区三区免费看| 欧美一区二区三区视频在线| 欧美一区二区三区免费视频| 在线成人免费观看| 欧美日本一区二区| 亚洲欧美日韩久久精品| 亚洲综合丝袜美腿| 麻豆国产精品视频| 成人精品视频一区二区三区| 欧美日韩午夜影院| 国产情人综合久久777777| 亚洲国产成人高清精品| 欧美精品一二三| 欧美不卡一区二区| 亚洲激情第一区| 天天操天天综合网| 国产精品一区二区三区乱码| 欧洲色大大久久| 国产精品成人一区二区三区夜夜夜| 亚洲伦理在线免费看| 老司机精品视频导航| 欧美日韩www| 国产精品少妇自拍| 六月丁香婷婷久久| 久久99热国产| 日韩精品一区二区三区在线观看 | 欧美一激情一区二区三区| 久久久久久免费网| 国产精品美女一区二区三区| 青青草国产精品亚洲专区无| 国产在线不卡一区| 欧美性做爰猛烈叫床潮| 中文字幕第一区二区| 亚洲人成伊人成综合网小说| 亚洲r级在线视频| 欧美日韩亚洲丝袜制服| 欧美一区二区三区在线视频| 日韩av高清在线观看| 欧美精品一区二区三| 国产中文字幕精品| 国产三级久久久| 国产精品一区二区不卡| 亚洲国产电影在线观看| 精品一区二区三区久久| 欧美tickling挠脚心丨vk| 日韩电影在线观看电影| 亚洲图片一区二区| 成人黄页毛片网站| 中国色在线观看另类| 一本色道综合亚洲| 亚洲成人激情综合网| 亚洲国产一区二区a毛片| 福利一区二区在线| 亚洲乱码国产乱码精品精小说| 色久综合一二码| 激情丁香综合五月| 亚洲一区二区三区三| 欧美美女一区二区| 国产盗摄一区二区| 日韩精品1区2区3区| 欧美一区二区三区在线电影| 国产一区 二区 三区一级| 久久精品夜夜夜夜久久| 国产91精品精华液一区二区三区| 国产亚洲欧美日韩在线一区| 亚洲国产精品麻豆| 福利电影一区二区| 久久久另类综合| 日韩成人av影视| 婷婷开心激情综合| 国产精品五月天| 欧美在线综合视频| 日韩一区二区在线观看视频| 国产91精品精华液一区二区三区| 欧美吞精做爰啪啪高潮| 久久精品一区二区三区不卡牛牛| 亚洲四区在线观看| 日韩一区二区三| 日本韩国一区二区三区| 国产精品影音先锋| 欧美疯狂做受xxxx富婆| 福利电影一区二区三区| 亚洲国产美女搞黄色| 4438亚洲最大| 久久成人av少妇免费| 欧美电影在线免费观看| 国产精品久久久久影院老司 | 日本韩国欧美一区| 一区二区三区四区蜜桃| 国产精品不卡一区二区三区| 91精品中文字幕一区二区三区| 在线观看网站黄不卡| 国产aⅴ精品一区二区三区色成熟| 五月激情丁香一区二区三区| 五月天精品一区二区三区| 亚洲成人激情自拍| 一本色道久久综合精品竹菊| 欧美日韩在线播放三区四区| 在线播放视频一区| 久久奇米777| 国产精品久久久久7777按摩| 国产网站一区二区| 2021国产精品久久精品| 国产精品国产三级国产普通话99 | 欧美一区二区免费观在线| 日韩一区二区中文字幕| 91在线精品秘密一区二区| 国内国产精品久久| 国产精品综合二区| 欧美一区二区三区在线看| 中文字幕欧美激情一区| 一区二区三区四区不卡视频 | 国产电影一区二区三区| 国产福利一区在线| 51精品久久久久久久蜜臀| 亚洲大片免费看| 91精品在线免费观看| 久久美女艺术照精彩视频福利播放| 日韩美女视频在线| xfplay精品久久| 亚洲黄一区二区三区| 国产精品中文字幕一区二区三区| 综合在线观看色| 在线免费观看日韩欧美| 日韩一区在线播放| 国产一区二区h| 国产精品丝袜91| 丁香另类激情小说| 亚洲国产岛国毛片在线| 欧美国产欧美亚州国产日韩mv天天看完整| 免费在线观看精品| 777午夜精品视频在线播放| 午夜精品久久久久久久久久久| 国产综合久久久久久久久久久久| 宅男噜噜噜66一区二区66| 日韩国产一二三区| 日韩情涩欧美日韩视频| 国产传媒日韩欧美成人| 国产精品日日摸夜夜摸av| 亚洲欧美日韩系列| 91丨九色丨尤物| 国产精品不卡在线观看| 国产成人免费视频一区| 亚洲国产精品高清| 色噜噜狠狠成人网p站| 男男gaygay亚洲| 国产色婷婷亚洲99精品小说| 国产 日韩 欧美大片| 国产精品欧美一区二区三区| 日韩亚洲欧美在线观看| 国产精品一级二级三级| 国产日产欧美一区二区三区| 91国偷自产一区二区开放时间| 舔着乳尖日韩一区| 这里只有精品99re| 欧美乱妇15p| 成年人国产精品| 五月激情丁香一区二区三区| 国产精品免费网站在线观看| 在线成人av影院| 成人黄动漫网站免费app| 免费观看30秒视频久久| 欧美日韩免费视频| 亚洲国产三级在线| 亚洲视频一区二区在线| 欧美激情中文字幕一区二区| 欧美一区二区成人| 国产精品亚洲午夜一区二区三区 | fc2成人免费人成在线观看播放| 国产午夜亚洲精品午夜鲁丝片| 欧美性高清videossexo| 91亚洲午夜精品久久久久久| 中文字幕中文字幕中文字幕亚洲无线| 国产美女一区二区| 国产精品一区专区| 一区二区在线看| 中文字幕精品综合| 日韩免费看网站| 国产精品色婷婷久久58| 99精品一区二区| 久久国产综合精品| 国产性色一区二区| 欧美经典一区二区三区| 久久精品免视看| 国产偷国产偷亚洲高清人白洁 | 从欧美一区二区三区| 福利一区二区在线| 国产三级三级三级精品8ⅰ区| 日本高清不卡视频| 欧美蜜桃一区二区三区| 综合久久一区二区三区| 免费人成网站在线观看欧美高清| 狠狠色丁香婷婷综合久久片|