Go創(chuàng)建一個(gè)包并使用(導(dǎo)入本地包和注意事項(xiàng))
Go 語言中,包(Package)的目的和其他語言中的庫或模塊是一樣的,支持模塊化、封裝、單獨(dú)編譯和重用。 ——《The Go Programming Language》
有時(shí)候需要自己寫一個(gè)包方便多次使用,但是在導(dǎo)入自己寫的包時(shí)遇到了問題。我以前以為import
部分直接就是包的路徑,但是實(shí)際自己寫了之后發(fā)現(xiàn)不是這樣的。這部分實(shí)際上這部分是可以解釋成一個(gè)標(biāo)識(shí)符,是由一個(gè)go.mod
文件確定,一般含義確實(shí)是路徑末端。
Go 中模塊的概念其實(shí)還包含了一部分版本管理的功能。所以 Go 的模塊和版本管理無論是學(xué)習(xí)還是開發(fā)都不是一件容易的事情,Go 團(tuán)隊(duì)也在一直努力調(diào)整和優(yōu)化。本文只能代表當(dāng)前版本go1.20.2
版本的情況,如果未來更新了我會(huì)進(jìn)行備注。
go.mod是什么
每個(gè) Go 的模塊都是由go.mod
確定,該文件描述了模塊的屬性,例如模塊存放的路徑是否依賴其他模塊、最低使用 Go 版本等信息。比如mod@v0.8.0
的go.mod
內(nèi)容為:
module golang.org/x/mod go 1.17 require golang.org/x/tools v0.1.12 // tagx:ignore
然后在編譯的時(shí)候,編譯器會(huì)去找有沒有這個(gè)標(biāo)識(shí)這個(gè)模塊的go.mod
,如果有的話找到對(duì)應(yīng)的xxx.go
,然后導(dǎo)入相應(yīng)的包中使用的功能進(jìn)行編譯。
這里有兩個(gè)問題:
- Go 在哪找模塊的?
- 如何讓 Go 從特定目錄下搜索包?
模塊(module)和包(package)的區(qū)別在于:模塊是一系列包的集合,并且在模塊文件結(jié)構(gòu)的根目錄下有個(gè)
go.mod
文件,自己甚至可以直接被編譯成一個(gè)程序。而包是某一個(gè)或多個(gè).go
文件,用來劃分包級(jí)別的作用域(package level),可以當(dāng)做其他語言的庫。范圍應(yīng)該是:模塊>>>包>>>源代碼文件。但是在某些情況下,包、模塊、庫這三個(gè)詞是可以混用的(在不同情況下叫法不同,但是卻指同一個(gè)東西)。
需要注意package main
是個(gè)例外,這并不是一個(gè)庫(盡管開頭有個(gè)package
),而是用來表示這是個(gè)可以單獨(dú)執(zhí)行的程序。
創(chuàng)建模塊和編寫包的內(nèi)容
這里舉個(gè)例子來進(jìn)行演示,演示的例子來自《The Go Programming Language》中 Section 2.7,是用來數(shù)一個(gè)數(shù)的二進(jìn)制有多少位為1
,比如輸入1
返回1
,輸入0x1234567890ABCDEF
返回32
。
新建一個(gè)文件夾popcount
,然后在里面創(chuàng)建一個(gè)名為popcount.go
的文件:
$ mkdir popcount $ cd popcount $ touch popcount.go
輸入以下內(nèi)容(下面這個(gè)算法不是最快的,也不是最容易理解的,但是可以解釋很多東西):
package popcount // pc[i]用來計(jì)數(shù)第i位是不是 var pc [256]byte //初始化包 func init() { for i := range pc { pc[i] = pc[i/2] + byte(i&1) } } // PopCount返回x有多少位為1. func PopCount(x uint64) int { return int(pc[byte(x>>(0*8))] + pc[byte(x>>(1*8))] + pc[byte(x>>(2*8))] + pc[byte(x>>(3*8))] + pc[byte(x>>(4*8))] + pc[byte(x>>(5*8))] + pc[byte(x>>(6*8))] + pc[byte(x>>(7*8))]) }
上文中:pc
首字母是小寫的,所以只能在popcount
包中使用,而PopCount
首字母是大寫的,所以可以在導(dǎo)入popcount
包的文件中使用。
繼續(xù)在popcount
中通過go mod init
命令創(chuàng)建go.mod
文件,如下:
$ go mod init test/popcount go: creating new go.mod: module test/popcount go: to add module requirements and sums: go mod tidy $ ls go.mod popcount.go
可以看到多了個(gè)go.mod
文件。
導(dǎo)入自建包(本地包)
然后在其他地方新建一個(gè)目錄pop_test
來編寫使用這個(gè)包的程序代碼(可以和popcount
在同一個(gè)目錄下,或者其他地方都行),這里選擇和popcount
在同一個(gè)目錄下,如下:
$ cd .. $ mkdir pop_test
然后在pop_test
中新建一個(gè)go.mod
:
$ go mod init pop_test
這時(shí)候go.mod
的內(nèi)容應(yīng)該是如下樣式:
module pop_test go 1.20
用你喜歡的文本編輯器打開它,在末尾添加這樣兩句話,變成如下樣式:
module pop_test go 1.20 require test/popcount v0.0.0 replace test/popcount => ../popcount
最后這兩句都不能省略,少一句都不行。
第一句是為了說明使用popcount
的版本,第二句是因?yàn)槲覀兪褂玫氖潜镜匕╨ocal package),而不是下載導(dǎo)入的庫,本地包的位置并不在GOROOT/src/test/popcount
中,Go 編譯的時(shí)候找不到的(關(guān)于GOROOT
后面還有一些內(nèi)容)。第二句話其實(shí)類似于 C 編譯器中的選項(xiàng)-I
。(這里解決了開頭的那兩個(gè)問題)
然后新建一個(gè)main.go
文件,輸入以下內(nèi)容:
package main import ( "fmt" "test/popcount" ) func main() { a := popcount.PopCount(0x1234567890ABCDEF) fmt.Println(a) }
這時(shí)候運(yùn)行應(yīng)該看到以下結(jié)果:
$ go run main.go
32
這種方法是官方推薦的,但是問題在于要在項(xiàng)目的根目錄(如上的pop_test
)下創(chuàng)建一個(gè)go.mod
。
第二種方法
下面這種方法是根據(jù)運(yùn)行機(jī)制進(jìn)行設(shè)置的,說實(shí)話并不是很方便管理,但是某些情況下卻挺方便的。
上文中提到:Go 默認(rèn)是在GOROOT/src
下尋找包的,某個(gè)包就是GOROOT/src/包名
。那么就可以直接在GOROOT/src
下按照包名的結(jié)構(gòu)放置自建的本地包,然后就可以在程序代碼中直接使用了,不用再在項(xiàng)目根目錄下創(chuàng)建一個(gè)go.mod
文件來說明使用的本地包的位置了。
通過以下命令找到你的GOROOT
,如下:
$ go env GOROOT /usr/local/go
你的可能不是/usr/local/go
。對(duì)于 Go 的這些環(huán)境變量最好使用go env
查看,如果你使用echo $GOROOT
可能會(huì)發(fā)現(xiàn)這個(gè)環(huán)境變量是空的。
此外,最好不要用expert
在 Shell 配置文件中修改這個(gè)環(huán)境變量,因?yàn)闃?biāo)準(zhǔn)庫都在默認(rèn)的GOROOT
中,一旦你切換了,那么這些標(biāo)準(zhǔn)庫你最好都復(fù)制到新位置。特殊情況下直接用expert
修改,但是只在當(dāng)前終端切換,不要徹底替換。
這種方法的最大弊端在于修改了/usr/local/go
,這些默認(rèn)目錄大部分時(shí)期是通過腳本自動(dòng)操作配置的,如果你進(jìn)行了修改,那么未來可能會(huì)出現(xiàn)問題和沖突,而你又忘了修改了這部分,那就是個(gè)很大的問題了。
所以如果必須用這種方法,最好創(chuàng)建一個(gè)不會(huì)重名(或者概率不大)的文件夾,比如ZhongUncle
,然后在里面創(chuàng)建包和配置go.mod
。
到此這篇關(guān)于Go創(chuàng)建一個(gè)包并使用(導(dǎo)入本地包和注意事項(xiàng))的文章就介紹到這了,更多相關(guān)Go創(chuàng)建包并導(dǎo)入內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go語言實(shí)現(xiàn)基于websocket瀏覽器通知功能
這篇文章主要介紹了Go語言實(shí)現(xiàn)基于websocket瀏覽器通知功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07Golang中 import cycle not allowed 問題
這篇文章主要介紹了Golang中 import cycle not allowed 問題的解決方法,問題從描述到解決都非常詳細(xì),需要的小伙伴可以參考一下2022-03-03使用Go實(shí)現(xiàn)郵箱驗(yàn)證碼API功能
本文將帶你了解一個(gè)項(xiàng)目如何實(shí)現(xiàn)一個(gè)郵箱驗(yàn)證接口,即一個(gè)可用的發(fā)送郵箱驗(yàn)證碼API和驗(yàn)證驗(yàn)證碼是否正確功能,對(duì)Go實(shí)現(xiàn)郵箱驗(yàn)證碼API詳細(xì)過程感興趣的朋友一起看看吧2024-06-06go?micro微服務(wù)框架項(xiàng)目搭建方法
這篇文章主要為大家介紹了go?micro微服務(wù)框架項(xiàng)目搭建方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01利用Go語言實(shí)現(xiàn)簡單Ping過程的方法
相信利用各種語言實(shí)現(xiàn)Ping已經(jīng)是大家喜聞樂見的事情了,網(wǎng)絡(luò)上利用Golang實(shí)現(xiàn)Ping已經(jīng)有比較詳細(xì)的代碼示例,但大多是僅僅是實(shí)現(xiàn)了Request過程,而對(duì)Response的回顯內(nèi)容并沒有做接收。而Ping程序不僅僅是發(fā)送一個(gè)ICMP,更重要的是如何接收并進(jìn)行統(tǒng)計(jì)。2016-09-09go module構(gòu)建項(xiàng)目的實(shí)現(xiàn)
本文主要介紹了go module構(gòu)建項(xiàng)目的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03