VSCode 開發 Go 程序也可以和 GoLand一樣強大
好的編程語言搭配好的開發工具,那必定是如虎添翼。Gopher 們應該都知曉 GoLand,這是 IDEA 專門為 Go 語言開發的集成開發環境(IDE)。此前 IDEA 對 Go 的支持是通過插件的,后來開發獨立的 IDE,可見 IDEA 看到了 Go 的發展和前景。
今天這篇文章,主要給大家介紹如何將 VSCode 打造成為一個強大的 Go 開發工具。
vscode-go 插件
打開 VSCode,切換到擴展搜索界面,輸入 go 搜索;或者打開一個 Go 源文件,VSCode 會建議你安裝 vscode-go 插件。
之所以叫 vscode-go,是因為在 GitHub 的項目名是這個,而在 VSCode 中,插件的名稱是 Go。該插件最初是微軟維護的,目前已經交給 Go Team 維護。
安裝完后,該插件會提示你安裝它的一些依賴。如果沒有提示,可以點擊 Analysis Tools Missing。最后點擊 Install 安裝。

在 Output 窗口會看到類似如下的輸出:
- Tools environment: GOPATH=/Users/xuxinhua/go
- Installing 13 tools at /Users/xuxinhua/go/bin in module mode.
- gocode gopkgs go-outline
- go-symbols
- guru gorename gotests dlv gocode-gomod godef goimports golint goplsInstalling github.com/mdempsky/gocode (/Users/xuxinhua/go/bin/gocode) SUCCEEDED
- Installing github.com/uudashr/gopkgs/v2/cmd/gopkgs (/Users/xuxinhua/go/bin/gopkgs) SUCCEEDED
- Installing github.com/ramya-rao-a/go-outline (/Users/xuxinhua/go/bin/go-outline) SUCCEEDED
- Installing github.com/acroca/go-symbols (/Users/xuxinhua/go/bin/go-symbols) SUCCEEDED
- Installing golang.org/x/tools/cmd/guru (/Users/xuxinhua/go/bin/guru) SUCCEEDED
- Installing golang.org/x/tools/cmd/gorename (/Users/xuxinhua/go/bin/gorename) SUCCEEDED
- Installing github.com/cweill/gotests/... (/Users/xuxinhua/go/bin/gotests) SUCCEEDED
- Installing github.com/go-delve/delve/cmd/dlv (/Users/xuxinhua/go/bin/dlv) SUCCEEDED
- Installing github.com/stamblerre/gocode (/Users/xuxinhua/go/bin/gocode-gomod) SUCCEEDED
- Installing github.com/rogpeppe/godef (/Users/xuxinhua/go/bin/godef) SUCCEEDED
- Installing golang.org/x/tools/cmd/goimports (/Users/xuxinhua/go/bin/goimports) SUCCEEDED
- Installing golang.org/x/lint/golint (/Users/xuxinhua/go/bin/golint) SUCCEEDED
- Installing golang.org/x/tools/gopls (/Users/xuxinhua/go/bin/gopls) SUCCEEDED
目前因為 gopls 還屬于 Beta 階段,默認情況下未啟用。因此你的輸出應該沒有 gopls 的安裝。一旦啟用了 gopls,VSCode 會提示你安裝 gopls,確認安裝即可。
注意:因為以上工具有些需要科學上網才能下載,因此請務必做了如下的配置,啟用 GOPROXY:
- go env -w GOPROXY=https://goproxy.cn,direct
同時建議 Go 版本 1.13+
還有一個小提示:自從有了 Module,GOPATH 漸漸淡出視野。然而,目前 go get 安裝 binary 會安裝到默認的 GOPATH (即 $HOME/go),為了讓上面那些工具方便使用,建議將$HOME/go/bin 加入 PATH 環境變量中。(你可以通過 VSCode 的配置:go.toolsGopath 修改工具的安裝位置)。
此外,可以通過 Command Palette 命令窗口,搜索 Go: Install/Update Tools 來更新或安裝上面的工具。
這些工具的作用
上面安裝了一堆的工具,正是因為類似的工具,讓 VSCode 這樣的文本編輯器可以更好地開發 Go 語言項目。
gocode 和 gocode-gomod
在早期,gocode 對于使用 Sublime Text 之類開發 Go 語言項目的小伙伴來說,功不可沒。最早的項目是 https://github.com/nsf/gocode,之后不維護,mdempsky fork 了一份,繼續維護 https://github.com/mdempsky/gocode。然而,Go 1.11 開始,由于 Module 的出現,gocode 不再好使,因為它只支持 GOPATH 項目,于是又出現了另一個 fork:https://github.com/stamblerre/gocode,這就是 gocode-gomod。
然而,隨著 gopls 的出現,以上三個項目都建議直接使用過 Go Language Server,即 gopls。因此對于 gocode,你可以忽略。
gopkgs
這是 go list all 命令的替代者,用于列出可用的 Go 包,速度比 go list all 更快。
go-outline
將 Go 源碼中的聲明提取為 JSON 的工具。
go-symbols
用于從 go 源代碼樹中提取包符號的 JSON 表示。
guru
為編輯器提供 Go 代碼導航功能的工具。Go 官方提供。用戶手冊見:http://golang.org/s/using-guru。由于有了 gopls,這個不需要了。
gorename
從名稱就知道是干嘛的。
gotests
從源代碼自動生成 Go 測試樣板文件。
delve
不用介紹吧,這是專為 Go 的調試器。
godef
查找源碼中的符號(symbols)信息。
goimports
自動導入缺失或移除多余的 import。同時還兼帶有 gofmt 的功能。
golint
官方的 Go 源碼 linter。實際中大家更喜歡 golangci-lint,它更快,支持并行,而且可以使用緩存,支持 yaml 配置等。VSCode 的配置中支持修改 Linter Tool,默認使用的 golint。當你修改為其他的,而系統沒有安裝對應的工具時,VSCode 會提示你安裝。另外,從 revive 的項目中看到,使用它的也不少。

小結
隨著你修改 VSCode 的配置,可能還會安裝其他的工具,這里不一一介紹。你遇到了,看一下它的 GitHub 首頁,就大概知道它的用途了。你也可以在這里查看到 vscode-go 插件使用的所有工具列表:https://github.com/golang/vscode-go/blob/master/docs/tools.md,將依賴的工具大概分成了 4 大類:工具鏈、文檔類、格式化類和診斷類。
另外值得一提的是,當你使用 gopls 時,大部分的工具是不需要的。
配置 vscode-go 插件
vscode-go 插件幾乎是開箱即用的。但由于目前 gopls 默認未啟用,需要做一些簡單的配置。先針對 go 和 go.mod 進行如下配置:(與是否啟用 gopls 無關)
- "[go]": {
- "editor.formatOnSave": true,
- "editor.codeActionsOnSave": {
- "source.organizeImports": true,
- }, // Optional: Disable snippets, as they conflict with completion ranking.
- "editor.snippetSuggestions": "none",
- },"[go.mod]": {
- "editor.formatOnSave": true,
- "editor.codeActionsOnSave": {
- "source.organizeImports": true,
- },},
其他配置的核心圍繞著 gopls 進行,官方建議,如果你使用了 Module,你應該啟用 gopls。不過啟用 gopls 之前你需要確保:
- 你的 Go 版本 >= 1.12;
- 你的項目使用了 Module;
如果你還在使用低版本或使用 GOPATH,建議你該升級了。Module 是未來,使用 VSCode,gopls 也是未來。
打開 VSCode 的配置,找到 Extensions 中的 Go,發現配置項不少。大部分都是針對上面那一堆工具的配置??梢娺@個擴展的功能最初是通過使用上面一系列的命令行工具實現的。這引入了復雜性,因為每個特性都是由不同的工具提供的。在上篇介紹 LSP 的文章中提到,Language Server 使所有編輯器支持所有編程語言,而不需要這些個性化的工具。它們還提供了速度改進,因為它們可以緩存和重用結果。
- 如果你就是不想使用 gopls,這里列出了該插件支持的所有配置 https://github.com/golang/vscode-go/blob/master/docs/settings.md#detailed-list,在眾多配置中,如果某個配置有這樣的語句:Not applicable when using the language server ,表示 gopls 模式下該配置無效。
因此,我們不糾結之前的那些,只關注 gopls 相關的配置。(可以通過打開 Command Palette,搜索 Open Settings,直接打開配置文件)
啟用 gopls
打開 VSCode 配置界面,定位到 Extensions -> Go 中,找到 Use Language Server,勾選上。

對應的配置是:"Go.useLanguageServer": true。如果你本地沒有安裝 gopls,會提示安裝。如果沒有提示,可以運行 Go: Install/Update Tools 命令并選擇 gopls 進行安裝。當 gopls 有更新時,VSCode 會自動更新。
配置 gopls
針對 gopls 有三項配置:
- go.languageServerExperimentalFeatures:允許你禁用某些功能,一些實驗性的特性;支持 diagnostics 和 documentLink,分別表示禁用診斷警告和禁用文檔鏈接;一般不需要配置;
- go.languageServerFlags:允許將 flags 傳遞給 gopls 進程;這個需要先了解下 gopls 命令的 flags;
- gopls:目前 VSCode 不認,但起作用;
關于第 3 個配置 gopls,支持的配置列表參考:https://github.com/golang/tools/blob/master/gopls/doc/settings.md,比如:
- "gopls": {
- "usePlaceholders": true,
- "completeUnimported": true
- }
關于第 2 個配置,在后面專門介紹。一般我們只需要設置如下配置即可,vscode-go 的配置就算完成。
- "go.useLanguageServer": true,
- "[go]": {
- "editor.formatOnSave": true,
- "editor.codeActionsOnSave": {
- "source.organizeImports": true,
- }, // Optional: Disable snippets, as they conflict with completion ranking. "editor.snippetSuggestions": "none",
- },"[go.mod]": {
- "editor.formatOnSave": true,
- "editor.codeActionsOnSave": {
- "source.organizeImports": true,
- },},"go.trace.server": "verbose",
- "gopls": {
- // Add parameter placeholders when completing a function.
- "usePlaceholders": false,
- // If true, enable additional analyses with staticcheck.
- // Warning: This will significantly increase memory usage. "staticcheck": false,
- },"go.languageServerFlags": [
- "-remote=auto", "-logfile=auto", "-debug=:0", "-rpc.trace",
- ]
再談 gopls
gopls 涉及到的內容很多,這里主要聊聊和 VSCode 編輯器相關的部分。
當在 VSCode 中啟用 Use Language Server 時,它會啟動一個 gopls 進程,即它就是 LSP 的實現,VSCode 通過 vscode-go 和 gopls 通訊。
看看 gopls 命令提供了哪些功能:
- $ gopls -h
- The Go Language source tools.Usage: gopls [flags] <command> [command-flags] [command-args]gopls is a Go language server. It is typically used with an editor to provide
- language features. When no command is specified, gopls will default to the 'serve'
- command. The language features can also be accessed via the gopls command-line interface.Available commands are:main: serve : run a server for Go code using the Language Server Protocol
- version : print the gopls version information
- bug : report a bug in gopls
- features: check : show diagnostic results for the specified file
- definition : show declaration of selected identifier
- folding_ranges : display selected file's folding ranges
- format : format the code according to the go standard
- highlight : display selected identifier's highlights
- implementation : display selected identifier's implementation
- imports : updates import statements
- inspect : inspect server state (daemon mode only)
- links : list links in a file
- prepare_rename : test validity of a rename operation at location
- references : display selected identifier's references
- rename : rename selected identifier signature : display selected identifier's signature
- fix : apply suggested fixes
- symbols : display selected file's symbols
- workspace_symbol : search symbols in workspace
- gopls flags are: -debug string serve debug information on the supplied address
- -listen string address on which to listen for remote connections. If prefixed by 'unix;', the subsequent address is assumed to be a unix domain socket. Otherwise, TCP is used.
- -listen.timeout duration when used with -listen, shut down the server when there are no connected clients for this duration
- -logfile string filename to log to. if value is "auto", then logging to a default output file is enabled
- -mode string no effect
- -ocagent string the address of the ocagent (e.g. http://localhost:55678), or off (default "off")
- -port int port on which to run gopls for debugging purposes
- -profile.cpu string write CPU profile to this file
- -profile.mem string write memory profile to this file
- -profile.trace string write trace log to this file
- -remote string forward all commands to a remote lsp specified by this flag. With no special prefix, this is assumed to be a TCP address. If prefixed by 'unix;', the subsequent address is assumed to be a unix domain socket. If 'auto', or prefixed by 'auto;', the remote address is automatically resolved based on the executing environment.
- -remote.debug string when used with -remote=auto, the -debug value used to start the daemon
- -remote.listen.timeout duration when used with -remote=auto, the -listen.timeout value used to start the daemon (default 1m0s)
- -remote.logfile string when used with -remote=auto, the -logfile value used to start the daemon
- -rpc.trace print the full rpc trace in lsp inspector format
- -v verbose output -vv very verbose output
相關的子命令和 flags 不少。
默認情況下,每次啟動一個 VSCode 窗口,gopls 進程就會多一個。因為 gopls 需要維護大量的緩存,方便對編輯的源代碼進行分析。因此,這種工作模式會導致 gopls 占用太多資源。
為了解決此類問題,gopls 支持一種新的模式,即啟動一個單一的、持久的、共享的 gopls “守護進程” 負責管理所有 gopls 會話。在這種模式下,編輯器的每一個窗口依然會啟動一個新的 gopls,不過這個 gopls 只是充當轉發器,負責將 LSP 轉發到那個共享的 gopls 實例,并記錄相關指標、日志和 rpc 跟蹤,因此這個 gopls 占用資源很少。
要使用共享 gopls 實例,必須有一個守護進程。你可以手動啟動,不過更方便的是讓 gopls 轉發器進程根據需要啟動共享守護進程。具體來說是使用 -remote=true 這個 flag:
- gopls -remote=auto -logfile=auto -debug=:0 -remote.debug=:0 -rpc.trace
對于 VSCode 來說就是上文看到的如下配置:
- "go.languageServerFlags": [
- "-remote=auto", "-logfile=auto", "-debug=:0", "-rpc.trace",
- ]
這將導致該進程在需要時自動啟動 gopls 守護進程,連接到它并轉發 LSP。
注意,在沒有連接客戶端的情況下,共享 gopls 進程將在一分鐘后自動關閉。
關于共享 gopls 更多的內容,可以查看 https://github.com/golang/tools/blob/master/gopls/doc/daemon.md 文檔。
另外上面配置中還有一個未提到:
- "go.trace.server": "verbose",
這用于在 Output 中輸出客戶端和 gopls Server 的通訊,方便調試,根據需要開啟。
此外,你應該想到了,gopls 還支持遠程開發。(上篇文章有人問,如果沒有網絡怎么辦。gopls 默認是在本地啟動服務的,所以不需要有網絡,但這個遠程開發就需要有網絡了)對遠程開發感興趣的,可以查看文檔:https://github.com/golang/tools/blob/master/gopls/doc/vscode.md#vscode-remote-development-with-gopls。
體驗下強大的 VSCode
到這里,一個強大的 Go 語言開發環境就搞定了。來體驗一下吧。
以 studygolang 源碼為例,下載源碼:
- $ git clone https://github.com/studygolang/studygolang
打開 VSCode,選擇 File -> Open… 打開 studygolang 文件夾。打開 main.go 文件,分別嘗試如下功能:
- Code completion:輸入 fmt.Println 試試,看是否能正確提示;
- Hover:光標懸停在某個 symbol 上,看是否能正確出現文檔提示;
- Jump to definition:按住 Command(MacOS)或 CTRL(Linux 或 Windows) 點擊某個 symbol,能否正確跳轉到定義;
- Find references:在某個 symbol 上按 Shift + F12,能否正確顯示引用處;
- 。。。
不出意外,以上功能都應該正常。
另外就是調試,在玩轉 VSCode 系列教程第一篇已經簡單介紹了調試功能,這里不重復。
聊聊 Lint
Lint 是一個很有用的工具,各語言都會有。Go 語言也不例外,官方有一個工具 golint。然而,大家更喜歡第三方的 lint 工具,因為無論在性能、功能還是可定制性方面都更強大。VSCode 目前默認使用 golint,但還支持另外三種 lint 工具:
- golangci-lint
- revive
- staticcheck
這三個工具都不錯,其中 staticcheck 還受到了 Google 和 Go 的贊助,因此有人建議廢棄官方的 golint,同時將 staticcheck 設為默認,當然也有建議 revive 的,相關 issue[1]。不過已經確認的是 golint 會凍結、廢棄:issue 38968[2]。
這三個工具,每一個都涉及到不少內容。不過基本都是開箱即用,另外可以根據自己的需要進行定制。我目前沒有切換,還是用的 golint,原因有 2:
- golint 目前基本夠用,沒有過多折騰這塊;
- golint 的輸出在 VSCode 的 PROBLEMS 窗口,而其他三個都在 OUTPUT 窗口。不喜歡;
期待哪天它們三個中的某個轉正吧。
和 GoLand 還有差距?
之前文章有人提到,VSCode 是否可以做到和 GoLand 類似的,將第三方依賴在 Explorer 顯示。好比 GoLand 的 External Libraries。
研究了一下,可以這么實現。
- 打開 VSCode,將某個項目加入,例如上面 studygolang;
- File -> Save Workspace As… 保存 Workspace,比如命名為 studygolang;
- 在 Explorer 中單擊右鍵,選擇 Add Folder to Workspace…,找到 module 第三方庫的路徑,一般是 $HOME/go/pkg/mod;
- 打開 studygolang.code-workspace,folders 改為:
- "folders": [
- { "name": "studygolang",
- "path": "."
- }, { "name": "External Libraries",
- "path": "../../../go/pkg/mod"
- }]
注意兩個 name 的值。保存后,Explorer 變成這樣:

當瀏覽代碼導航到依賴的庫時,左邊 Explorer 也會定位到相應的目錄。整體和 GoLand 還是類似的。
最后建議一個 Go 項目一個 VSCode 窗口,這樣不會亂。
總結
講了這么多,VSCode 打造為 Go 的開發環境,你還滿意嗎?看看我的 VSCode 界面:

注:左邊 Explorer 漂亮的文件和文件夾圖標使用的是 vscode-icons 插件。
關于 VSCode 進行 Go 開發,如果你有其他疑問,歡迎留言交流。