Golang - 從 Hello World 認識 GOPATH

覺得我們的內容實用嗎?MyApollo 電子報讀者募集中!歡迎訂閱電子報!

初學 golang 的人應該都會對環境變數 GOPATH 感到困惑。

譬如 PYTHONPATH 是 Python 尋找模組與套件的路徑,一般來說並不需要特別設定,也可以用得很開心。

然而 GOPATH 則不一樣,一旦程式涉及 package 就會需要留心 GOPATH 的設定,很容易令人感到困惑,但是只要弄清楚 GOPATH 的基本,就能夠很輕鬆地開發 Go 應用程式。

那麼,就從 Hello World 開始認識 GOPATH 吧!

本文環境#

  • macOS 10.15
  • go 1.14.6

Hello World#

以下是 Go 的 Hello World 範例:

// hello.go
package main

import "fmt"

func main() {
	fmt.Printf("hello, world\n")
}

接著用以下指令編譯:

$ go build hello.go

最後執行剛剛編譯出來的程式看看,成功的話,就可以看到程式列印出 hello, world

$ ./hello

以上就是 Go 最簡單的程式。

截至目前為止,我們都還沒碰到 package.的部分,因此沒碰到 GOPATH ,接下來我們試著將列印 hello, world 的部分改為 package 進行模組化,再將之 import 至我們的主程式 main 中試試。

首先建立一個資料夾作為工作區:

$ mkdir $HOME/goworkspace

接著在該資料夾中新增 2 個檔案如下, hello.go 就是方才的 hello world 範例程式,而 tutor.go 則是一個用來存放列印 hello, world 的 package 。

.
├── hello.go
└── tutor.go

上述 2 個檔案的內容分別如下:

// tutor.go
package tutor

import "fmt"

func HelloWorld() {
    fmt.Println("hello, world")
}
// hello.go
package main

import t "tutor"

func main() {
    t.HelloWorld()
}

p.s. 本篇不贅述各種 package, import, func 等基本 golang 知識

目前我們已經在 tutor.go 中新增 1 個函式 HelloWorld() ,並且在 hello.go 中使用該 package ,並且呼叫 HelloWorld() 。

如果我們試圖編譯 hello.go 將會出現以下錯誤:

hello.go:3:8: cannot find package "tutor" in any of:
	/usr/local/go/src/tutor (from $GOROOT)
	/usr/local/go/bin/src/tutor (from $GOPATH)

原來是 Go 在編譯時無法找到 package 啊!這是由於 Go 會去 $GOROOT 與 $GOPATH 中試圖尋找 tutor 這個 package ,然而這些路徑底下並沒有我們剛剛寫的 tutor.go 。

這時候通常用慣其他程式語言的人就會感到相當困惑,為何當前目錄下的 package 並不會被載入呢?

GOPATH#

原來 GOPATH 其實是 go 工作區(workspace)的概念,你可以把所有的 Go 專案與 package 都放在 GOPATH 底下。

(我想應該是由於 monorepo 的概念而導致 GOPATH 如此機制)

先來看看 GOPATH 的值:

$ echo $GOPATH
/usr/local/go/bin/

原來 macOS 預設的 GOPATH 指向 /usr/local/go/bin/ 。但我們的 Go 工作區其實在 $HOME/goworkspace ,所以我們用以下指令修改 GOPATH 的值:

$ export GOPATH=$HOME/goworkspace

接著在 GOPATH 中新增 src 資料夾,這是 Go 規定會在 GOPATH 中尋找的資料夾,所以一定要新增,否則 Go 一樣會找不到 package:

$ mkdir -p $GOPATH/src

接著建立 1 個資料夾 tutor 存放 tutor.go ,這是由於 Go 規定 package 名稱必須與存放它的資料夾名稱一樣,最後將 tutor.go 移進 $GOPATH/src/tutor 中:

$ mkdir -p $GOPATH/src/tutor
$ mv tutor.go $GOPATH/src/tutor

截至目前為止,我們的專案資料夾結構會長這樣:

.
├── hello.go
└── src
    └── tutor
        └── tutor.go

設定好 GOPATH 與將 package 放進 src 資料夾後,編譯 hello.go 就正常了!

使用第 3 方套件#

前面談到 GOPATH 是工作區(workspace)的概念,所有 Go 專案都會存在 GOPATH 底下,包含第 3 方套件也是如此。

而現代開發應用也不太可能完全不使用第 3 方套件,接著我們試著使用套件將列印 hello, world 變成紅色的文字做為範例,看看 Go 會怎麼存放第 3 方套件。

首先我們將 tutor.go 改成以下,可以看到我們使用 github.com/fatih/color package 將文字變為紅色:

package tutor

import "github.com/fatih/color"

func HelloWorld() {
    color.Red("hello, world")
}

接著用以下指令安裝該 package :

$ go get github.com/fatih/color

安裝完後的 GOPATH 資料夾結構會變成以下:

.
├── hello
├── hello.go
├── pkg
│   └── darwin_amd64
│       └── github.com
│           └── fatih
└── src
    ├── github.com
    │   └── fatih
    │       └── color
    └── tutor
        └── tutor.go

可以看到 src 資料夾底下多了 github.com/fatih/color ,也正是因為 go get 自動將該套件的原始碼安裝到 src 資料夾底下,我們才能夠順利進行地 import 該模組。

P.s. 多出來的 pkg 中存放的是被預編譯好的 package ,用來加速編譯過程,通常不需要理會這個資料夾,如果該資料夾被刪除也沒關係, Go 會自行重建

也由於我們經常會透過 Github 開放 package/專案,所以通常就會將程式碼放在 src/github.com/<username>/<project> 路徑底下,並且對該資料夾進行版本控制,如此一來就能夠讓所有人都能夠用 go get 的方式安裝該 package/專案,方便許多(不過缺點則是程式碼不美觀與 src 資料夾各種 package 與自己的專案 package 混雜在一起)。

當然,如果沒有開放的打算,不這麼做也是可以的, Go 並沒有規定一定要如何存放你的程式碼,可以直接在 $GOPATH/src 底下建立專案資料夾進行管理,只要能夠讓 Go 順利找到 package 並順利完成編譯就可以了。

最後試著將所有的程式移進 $GOPATH/src/github.com/<your github username>/HelloGo 資料夾,並且用 git 進行版本控制:

$ mkdir -p src/github.com/<your github username>/HelloGo
$ git init src/github.com/<your github username>/HelloGo
$ mv hello.go src/github.com/<your github username>/HelloGo
$ mv src/tutor src/github.com/<your github username>/HelloGo

完成上述搬運後,只要將 hello.go 再次改成以下,就可以囉!

package main

import t "github.com/<your github username>/HelloGo/tutor"

func main() {
    t.HelloWorld()
}

最後可以編譯一次試試是否正常!

$ go build hello.go

如果正常的話,就可以將該專案上傳至 GitHub ,別人就能夠以 go get 的方式取得你的程式碼囉!

GOROOT#

最後談談 GOROOT ,其實 GOROOT 就是 Go 的指令、工具等存放的地方,一般也不太會存取它,所以其實不知道也沒關係,但也不建議將 GOROOT 當作 GOPATH 使用喔!

結語#

理解 GOPATH 之後,真的會對於 Go 的開發會相當有助益。

以上, Happy Coding!

References#

https://www.digitalocean.com/community/tutorials/understanding-the-gopath

The Go Programming Language

覺得內容實用嗎?

MyApollo 電子報讀者募集中!新文章與技術新知會直接寄到你的信箱。

訂閱電子報

對抗久坐職業傷害

研究指出每天增加 2 小時坐著的時間,會增加大腸癌、心臟疾病、肺癌的風險,也造成肩頸、腰背疼痛等常見問題。

然而對抗這些問題,卻只需要工作時定期休息跟伸展身體即可!

你想輕鬆改變現狀嗎?試試看我們的 PomodoRoll 番茄鐘吧!PomodoRoll 番茄鐘會根據你所設定的專注時間,定期建議你 1 項辦公族適用的伸展運動,幫助你打敗久坐所帶來的傷害!

馬上試用 PomodoRoll

贊助我們的創作

看完這篇文章了嗎? 休息一下,喝杯咖啡吧!

如果你覺得 MyApollo 有讓你獲得實用的資訊,希望能看到更多的技術分享,邀請你贊助我們一杯咖啡,讓我們有更多的動力與精力繼續提供高品質的文章,感謝你的支持!

Buy me a coffee

輸入關鍵字開始搜尋