[Golang] Modules and Packages | PJCHENder 未整理筆記

文章推薦指數: 80 %
投票人數:10人

How to Write Go Code @ golang. ... 如果套件是在module 中,go import package 的路徑會是 module path 加上 subdirectory 。

通常package 的名稱會 ... Skiptomaincontent這個網站放置的是未發佈或未完整整理的筆記內容,若想檢視正式的筆記內容請到PJCHENder那些沒告訴你的小細節。

PJCHENderOfficialDocsBlogGitHubFacebookLinkedin🌜🌞SearchOnthispageHowtoWriteGoCode@golang不論是module或package,都可以在本地匯入,不一定要發到遠端repository。

#在hello資料夾中$gomodinitexample.com/user/hello#宣告module_path,通常會和該repository的url位置一致$goinstall.#編譯該module並將執行檔放到GOBIN,因此在GOBIN資料夾中會出現hello的執行檔$gomodtidy#移除沒用到的套件$goclean-modcache#移除所有下載第三方套件的內容Copy💡安裝到GOBIN資料夾的檔案名稱,會是在go.mod檔案中第一行定義modulepath中路徑的最後一個。

因此若module_path是example.com/user/hello則在GOBIN中的檔名會是hello;若module_path是example/user則在GOBIN資料夾中的檔名會是user。

若我們在gomodule中有使用其他的遠端(第三方)套件,當執行goinstall、gobuild或gorun時,go會自動下載該remotemodule,並記錄在go.mod檔案中。

這些遠端套件會自動下載到$GOPATH/pkg/mod的資料夾中。

當有不同的module之間需要使用相同版本的第三方套件時,會共用這些下載的內容,因此這些內容會是「唯讀」。

若想要刪除這些第三方套件的內容,可以輸入goclean-modcache。

設定GOPATH​參考:Go起步安裝設定>設定GOPATH#~/.zshrcexportGOPATH=$HOME/goexportPATH=$PATH:$GOPATH/binCopyPackages​Go的程式碼都是以package的方式在組織,一個package就是在同一資料夾中的許多GO檔案。

同一個package的所有Go檔案會放在同一個資料夾內;而這個資料夾內的所有檔案也都會屬於同一個package,有相同的package名稱。

如果套件是在module中,goimportpackage的路徑會是modulepath加上subdirectory。

通常package的名稱會跟著folder的名稱,舉例來說,若檔案放在math/rand資料夾中,則該套件會稱作rand。

packagescope:在Go語言中,並沒有區分public、private或protected,而是根據變數名稱的第一個字母大小寫來判斷能否被外部引用。

在同一個package中變數、函式、常數和type,都隸屬於同一個packagescope,因此雖然可能在不同支檔案內,但只要隸屬於同一個package,都可以使用(visible)。

如果需要讓package內的變數或函式等能夠在package外部被使用,則該變數的第一個字母要大寫才能讓外部引用(Exportednames),否則的話會無法使用有兩種不同類型的package:executablepackage:是用來產生我們可以執行的檔案,一定會包含packagemain並且帶有名為main的函式,只有這個檔案可以被執行(run)和編譯(build),並且不能被其他檔案給匯入。

reusablepackage(librarypackage):類似"helpers"或常稱作library/dependency,目的是可以放入可重複使用的程式邏輯,它是不能被直接執行的,可以使用任何的名稱。

在Go裡面要區別這兩種Package的主要方式就是利用「package名稱」,當使用main當做package名稱時,就會被當作executablepackage,因此接著執行gobuild時,會產生一支執行檔;但是當使用main以外的名稱是,都會被當作是reusablepackage,因此當使用gobuild指令時,不會產生任何檔案。

要匯入reusablepackage只需要://匯入單一個packageimport"fmt"//匯入多個packages(不用逗號)import("fmt""strings")Copy//go-hello-world/main.gopackagemainimport("fmt"//把foo這個package的方法都放到這隻檔案中,如此不用使用foo.HelloWorld(不建議)."go-hello-world/foo"//將模組轉換為別名,可以使用bar.HelloWorldbar"go-hello-world/foo"//沒有用到這個package,但要init它_"go-hello-world/foo")funcmain(){fmt.Println(bar.HelloWorld())fmt.Println("Hellomain")}Copy//go-hello-world/foo/helloworld.gopackagefooimport"fmt"funcinit(){fmt.Println("Thisisinitofhelloworld")}//HelloWorld...funcHelloWorld()string{return"HelloWorld"}Copypackagename:codingstyleandconvention​👍packagename@golangblogpackagename@effectivegopackagename@golangwiki>codereviewcomments在Go中,package的名稱應該是短而清楚,以小寫(lowercase)命名,同時不包含底線(under_scores)或小寫駝峰(mixedCaps),並且通常會是名詞(noun),例如time、list、或http。

在幫package命名的時候,試想自己就是使用該pkg的開發者,用這種角度來替自己的pkg命名。

另外,由於使用者在匯入該package,假設引入的使用時,一定會需要使用該package的name作為前綴,因此在package中的變數名稱盡可能不要和packagename重複:在httppackage中如果要使用Server,不需要使用http.HTTPServer,而是可以直接使用http.Server當在uuid的package要產生一組uuid.UUID時,不需要使用uuid.NewUUID()的方法,而是可以直接使用uuid.New(),也就是說如果回傳的型別名稱(UUID)和該pkg的名稱相同時,可以直接將該方法命名成New,而不用是NewOOOtime.Now()會回傳time.Time如果pkg會回傳的struct名稱不同於package本身的名稱時,則可以使用NewOOOtime.NewTicker()uuid.NewRandom()💡雖然pkg中variablename的前綴會盡量不和packagename重複,但很常見的情況是在該pkg中有其同名的struct,例如timepkg中有名為Time的struct,因此型別會是time.Time,不好的用法:盡可能不要使用util,common,misc這類的名稱作為packagename,因為這對使用者來說是沒有意義的名字,而是去想使用者這如果要用這些方法的話,最有可能使用到的關鍵字是什麼。

見範例「Breakupgenericpackages」gotool找package的邏輯​gotool會使用$GOPATH來找對應的package,假設引入的package路徑是"github.com/user/hello",那麼gotool就會去找$GOPATH/src/github.com/user/hello。

Modules​#初始化GoModule$exportGO111MODULE=on#在GOPATH外要使用module需要啟動#gomodinit[module_path]$gomodinitexample.com/user/hello#宣告modulepath$gomodtidy#移除沒用到的library$gomoddownload#下載套件(gobuild和gotest也會自動下載)$goget[library]#新增或更新package到Module內$goget-u./...#等同於,goget-u=patch./...$gogetfoo@master.#下載特定版本的gopackage$golist-mall#印出module正在使用的所有套件$golist-m-versions[package]#列出所有此套件可下載的版本$golist-u-mall#檢視有無任何minor或patch的更新CopyModules@GolangWikiUsingGoModules@golangblog在一個專案中通常只會有一個module(但也可以有多個),並且放在專案的根目錄,module裡面會集合所有相關聯的Gopackages。

在go.mod中會宣告modulepath,這是用來匯入所有在此module中的路徑的前綴(pathprefix),同時它也讓go的工具知道要去哪裡下載它。

透過Modules可以準確紀錄相依的套件,讓程式能再次被編譯。

總結來說:一個repository會包含一個或以上的Gomodules每個module會包含一個或以上的Gopackages每個package會包含一個或以上的檔案在單一資料夾中在執行gobuild或gotest時,會根據imports的內容自動添加套件,並更新go.mod。

當需要的時候,可以直接在go.mod指定特定的版本,或使用goget,例如[email protected],gogetfoo@master,[email protected]​在rootdirectory中會透過go.mod來定義Module,而Module的原始碼可以放在GOPATH外,有四種指令module,require,replace,exclude可以使用://go.mod//go.modmodulegithub.com/my/thingrequire(github.com/some/dependencyv1.2.3github.com/another/dependency/v4v4.0.0)Copymodule​用來宣告Module的身份,並帶入module的路徑。

在這個module中所有匯入的路徑都會以這個modulepath當作前綴(prefix)。

透過module的路徑,以及go.mod到package's資料夾的相對路徑,會共同決定importpackage's時要使用的路徑。

replaceandexecute​這兩個命令都只能用在當前模組(即,main),否則將會在編譯時被忽略。

其他​階層關係上:Module>Package>Directory跨檔案引用函式​從下面的例子中可以看到,雖然main.go裡面有一個函式是定義在state.go的檔案中,但因為它們屬於同一個package,所以當從Terminal執行gorunmain.gostate.go時,程式可以正確執行。

或者也可以輸入gorun*.go://main.gopackagemainfuncmain(){printState()}Copy//state.gopackagemainimport"fmt"funcprintState(){fmt.Println("California")}Copy套件載入的流程​在golang中,使用某一個套件時,go會先去GOROOT找看看是不是內建的函式庫,如果找不到的話,會去GOPATH內找,如果都找不到的話,就無法使用。

參考​HowToWritePackagesinGobyGopherGuides@DigitalOceanCommunityGo:TheCompleteDeveloper'sGuide(Golang)@UdemybyStephenGriderGo語言基礎實戰(開發,測試及部署)@UdemybyBo-YiWuGo(Golang):TheCompleteBootcamp@UdemybyJosePortillaPrevious«[go]mapsNext[note]Goconcurrency»設定GOPATHPackagespackagename:codingstyleandconventiongotool找package的邏輯Modulesgo.mod其他跨檔案引用函式套件載入的流程參考



請為這篇文章評分?