動態

詳情 返回 返回

Go 官方推薦的 Go 項目文件組織方式 - 動態 詳情

公眾號首發:https://mp.weixin.qq.com/s/JwEPt3oZ3aY8ZzKddwnpiA

剛開始接觸 Go 的開發者大概都會遇到一個問題:我該如何組織我的 Go 項目?這種問題當然沒有標準答案,不過 Go 官方下場,給了廣大 Gopher 一個推薦模板。本文就來帶大家一起來學習一下 Go 官方對於 Go 項目佈局的指導原則。

本文以 Go 官方博客「Organizing a Go module」為基石進行講解。

基礎 Go 包

對於最基礎的 Go 包,我們可以按照如下方式組織:

project-root-directory/
  go.mod
  modname.go
  modname_test.go

所有代碼都位於項目的根目錄下,這個項目由一個模塊(module)組成,而這個模塊又由一個包(package)組成。

假設這個項目會上傳到 GitHub 倉庫 github.com/someuser/modname 中,那麼 go.mod 文件中的第一行(module line)應寫為:

module github.com/someuser/modname

modname.go 文件中的代碼使用如下命令聲明一個 modname 包:

package modname

// ... package code here

在其他 Go 項目中,可以通過如下方式導入這個 Go 包:

import "github.com/someuser/modname"

此外,一個 Go 包其實可以被拆分成多個文件:

project-root-directory/
  go.mod
  modname.go
  modname_test.go
  auth.go
  auth_test.go
  hash.go
  hash_test.go

這裏所有 Go 文件都屬於同一個包,即都會聲明為 package modname

NOTE:

不知道你有沒有注意,示例中的項目名稱 project-root-directory 使用短橫線來連接多個單詞,而 Go 文件名則使用單詞直接連寫的形式 modname.go(而非 mod_name.go),這也是 Go 的一貫風格,雖然沒有強制約定,但看多了社區中優秀的 Go 代碼,你就會有所體會。

關於這點更加深入的探討,你可以閲讀我曾寫過文章《Go 項目文件命名規範是什麼?》來進行學習。

可執行的 Go 程序

Go 可執行程序(或命令行程序)一般根據複雜程度來構建目錄,最小的 Go 程序可以僅定義一個包含 main 函數的 Go 文件,如果功能較多,可以將其拆分為多個文件:

project-root-directory/
  go.mod
  auth.go
  auth_test.go
  client.go
  main.go

main.go 中存放了 main 函數,不過這只是一個約定俗成的做法,你可以將其放到任何合法的 xxx.go 中。

當拆分為多個文件,如果 main.go 引用了其他文件中的代碼,這個時候就不能簡單的使用 go run main.go 來執行 Go 程序了,可以按照如下方式執行:

$ go run .

並且,用户可以使用以下命令將 Go 程序安裝到自己的主機上:

$ go install github.com/someuser/modname@latest

更復雜的 Go 程序

如果一個 Go 包或者 Go 可執行程序更加複雜,則可以按照如下方式組織目錄結構:

project-root-directory/
  internal/
    auth/
      auth.go
      auth_test.go
    hash/
      hash.go
      hash_test.go
  go.mod
  modname.go
  modname_test.go

這裏還演示了使用 modname.go 作為程序的入口,而非命名為 main.go

internal/ 目錄下的所有包都不會被公開,其他程序無法引用。這是 Go 語言層面限制,強制的,不僅僅是約定俗成。這樣,我們就可以隨時隨地的重構 internal/ 目錄中的代碼,而不必擔心影響其他程序。

當然,modname.go 中可以導入 internal/ 目錄下的包,因為它們本來就是一個程序。在 modname.go 中導入 auth 包:

import "github.com/someuser/modname/internal/auth"

包含多個包的 Go 程序

我們知道,一個 Go 模塊(module)可以由多個包(package)組成,而每個包都可以有自己的子目錄。

我們可以組織成一個層次結構更深的 Go 程序:

project-root-directory/
  go.mod
  modname.go
  modname_test.go
  auth/
    auth.go
    auth_test.go
    token/
      token.go
      token_test.go
  hash/
    hash.go
  internal/
    trace/
      trace.go

這個目錄看起來更符合一個真實的 Go 包。

假設 go.mod 中聲明 module 如下:

module github.com/someuser/modname

modname.go 位於項目根目錄,聲明包為 modname,用户在使用時則可以按照如下方式導入此包:

import "github.com/someuser/modname"

也可以按照如下方式導入子包:

import "github.com/someuser/modname/auth"
import "github.com/someuser/modname/auth/token"
import "github.com/someuser/modname/hash"

注意:internal/trace 無法被外部程序導入。

包含多個可執行的 Go 程序

有時候,我們可能會在一個 Git 倉庫中包含多個可執行的 Go 程序,可以按照如下方式組織目錄:

project-root-directory/
  go.mod
  internal/
    ... shared internal packages
  prog1/
    main.go
  prog2/
    main.go

prog1/prog2/ 中分別有自己的 main.go 文件,即兩個獨立的可執行 Go 程序。

prog1/prog2/ 可以共享根目錄中的其他包或子包。

我們可以按照如下方式分別安裝二者到主機上:

$ go install github.com/someuser/modname/prog1@latest
$ go install github.com/someuser/modname/prog2@latest

其實,針對一個 Git 倉庫中包含多個可執行的 Go 程序的情況,我們還有更好的做法來組織目錄:

project-root-directory/
  go.mod
  modname.go
  modname_test.go
  auth/
    auth.go
    auth_test.go
  internal/
    ... internal packages
  cmd/
    prog1/
      main.go
    prog2/
      main.go

將可執行文件都放到 cmd/ 目錄下也是約定俗成的做法。下次,當你見到 cmd/ 目錄,就應該想到這個目錄是幹什麼的。

現在可執行程序的安裝命令如下:

$ go install github.com/someuser/modname/cmd/prog1@latest
$ go install github.com/someuser/modname/cmd/prog2@latest

服務器項目

其實,我們在用 Go 編寫程序時,大多數是用來實現 Go Web Server 程序,這也是 Go 最常見的使用場景,Go 是實現服務器的通用語言選擇。

比如 Kubernetes 項目,其最核心的組件也是 Server 程序。

通常,我們可以按照如下方式來組織 Go 服務器項目:

project-root-directory/
  go.mod
  internal/
    auth/
      ...
    metrics/
      ...
    model/
      ...
  cmd/
    api-server/
      main.go
    metrics-analyzer/
      main.go
    ...
  ... the project's other directories with non-Go code

如果你有過 Go Web 開發經驗,是不是很熟悉這個目錄結構?

這已經到了廣大 Gopher 最熟悉的領域,接下來,我就不過多講解了,你可以繼續閲讀我寫的另一篇文章《如何設計一個優秀的 Go Web 項目目錄結構》,裏面介紹了開源項目 https://github.com/golang-standards/project-layout 對 Go Web 項目組織的最佳實踐。

總結

我們學習了 Go 官方推薦的項目佈局的指導原則,現在我們對於 Go 包和 Go 可執行程序的目錄組織方式,都有了較為清晰的認知。

此外,我們還順便學習瞭如何安裝 Go 可以執行程序,可以通過 go install xxx 來安裝。

對於廣大 Gopher,接觸最多的應該是 Go Web 服務器的開發。對於 Go Web 項目,不僅 Go 官方給出了指導原則,我們還可以參考 project-layout 項目學習一個大型的 Go 項目是如何佈局的。

希望此文能對你有所啓發。

聯繫我

  • 公眾號:Go編程世界
  • 微信:jianghushinian
  • 郵箱:jianghushinian007@outlook.com
  • 博客:https://jianghushinian.cn
  • GitHub:https://github.com/jianghushinian
user avatar beiyouzhiyu 頭像 bug1412 頭像
點贊 2 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.