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

在 Output 窗口會(huì)看到類似如下的輸出:
- 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
目前因?yàn)?gopls 還屬于 Beta 階段,默認(rèn)情況下未啟用。因此你的輸出應(yīng)該沒有 gopls 的安裝。一旦啟用了 gopls,VSCode 會(huì)提示你安裝 gopls,確認(rèn)安裝即可。
注意:因?yàn)橐陨瞎ぞ哂行┬枰茖W(xué)上網(wǎng)才能下載,因此請(qǐng)務(wù)必做了如下的配置,啟用 GOPROXY:
- go env -w GOPROXY=https://goproxy.cn,direct
同時(shí)建議 Go 版本 1.13+
還有一個(gè)小提示:自從有了 Module,GOPATH 漸漸淡出視野。然而,目前 go get 安裝 binary 會(huì)安裝到默認(rèn)的 GOPATH (即 $HOME/go),為了讓上面那些工具方便使用,建議將$HOME/go/bin 加入 PATH 環(huán)境變量中。(你可以通過 VSCode 的配置:go.toolsGopath 修改工具的安裝位置)。
此外,可以通過 Command Palette 命令窗口,搜索 Go: Install/Update Tools 來(lái)更新或安裝上面的工具。
這些工具的作用
上面安裝了一堆的工具,正是因?yàn)轭愃频墓ぞ?,?VSCode 這樣的文本編輯器可以更好地開發(fā) Go 語(yǔ)言項(xiàng)目。
gocode 和 gocode-gomod
在早期,gocode 對(duì)于使用 Sublime Text 之類開發(fā) Go 語(yǔ)言項(xiàng)目的小伙伴來(lái)說,功不可沒。最早的項(xiàng)目是 https://github.com/nsf/gocode,之后不維護(hù),mdempsky fork 了一份,繼續(xù)維護(hù) https://github.com/mdempsky/gocode。然而,Go 1.11 開始,由于 Module 的出現(xiàn),gocode 不再好使,因?yàn)樗恢С?GOPATH 項(xiàng)目,于是又出現(xiàn)了另一個(gè) fork:https://github.com/stamblerre/gocode,這就是 gocode-gomod。
然而,隨著 gopls 的出現(xiàn),以上三個(gè)項(xiàng)目都建議直接使用過 Go Language Server,即 gopls。因此對(duì)于 gocode,你可以忽略。
gopkgs
這是 go list all 命令的替代者,用于列出可用的 Go 包,速度比 go list all 更快。
go-outline
將 Go 源碼中的聲明提取為 JSON 的工具。
go-symbols
用于從 go 源代碼樹中提取包符號(hào)的 JSON 表示。
guru
為編輯器提供 Go 代碼導(dǎo)航功能的工具。Go 官方提供。用戶手冊(cè)見:http://golang.org/s/using-guru。由于有了 gopls,這個(gè)不需要了。
gorename
從名稱就知道是干嘛的。
gotests
從源代碼自動(dòng)生成 Go 測(cè)試樣板文件。
delve
不用介紹吧,這是專為 Go 的調(diào)試器。
godef
查找源碼中的符號(hào)(symbols)信息。
goimports
自動(dòng)導(dǎo)入缺失或移除多余的 import。同時(shí)還兼帶有 gofmt 的功能。
golint
官方的 Go 源碼 linter。實(shí)際中大家更喜歡 golangci-lint,它更快,支持并行,而且可以使用緩存,支持 yaml 配置等。VSCode 的配置中支持修改 Linter Tool,默認(rèn)使用的 golint。當(dāng)你修改為其他的,而系統(tǒng)沒有安裝對(duì)應(yīng)的工具時(shí),VSCode 會(huì)提示你安裝。另外,從 revive 的項(xiàng)目中看到,使用它的也不少。

小結(jié)
隨著你修改 VSCode 的配置,可能還會(huì)安裝其他的工具,這里不一一介紹。你遇到了,看一下它的 GitHub 首頁(yè),就大概知道它的用途了。你也可以在這里查看到 vscode-go 插件使用的所有工具列表:https://github.com/golang/vscode-go/blob/master/docs/tools.md,將依賴的工具大概分成了 4 大類:工具鏈、文檔類、格式化類和診斷類。
另外值得一提的是,當(dāng)你使用 gopls 時(shí),大部分的工具是不需要的。
配置 vscode-go 插件
vscode-go 插件幾乎是開箱即用的。但由于目前 gopls 默認(rèn)未啟用,需要做一些簡(jiǎn)單的配置。先針對(duì) go 和 go.mod 進(jìn)行如下配置:(與是否啟用 gopls 無(wú)關(guān))
- "[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 進(jìn)行,官方建議,如果你使用了 Module,你應(yīng)該啟用 gopls。不過啟用 gopls 之前你需要確保:
- 你的 Go 版本 >= 1.12;
- 你的項(xiàng)目使用了 Module;
如果你還在使用低版本或使用 GOPATH,建議你該升級(jí)了。Module 是未來(lái),使用 VSCode,gopls 也是未來(lái)。
打開 VSCode 的配置,找到 Extensions 中的 Go,發(fā)現(xiàn)配置項(xiàng)不少。大部分都是針對(duì)上面那一堆工具的配置??梢娺@個(gè)擴(kuò)展的功能最初是通過使用上面一系列的命令行工具實(shí)現(xiàn)的。這引入了復(fù)雜性,因?yàn)槊總€(gè)特性都是由不同的工具提供的。在上篇介紹 LSP 的文章中提到,Language Server 使所有編輯器支持所有編程語(yǔ)言,而不需要這些個(gè)性化的工具。它們還提供了速度改進(jìn),因?yàn)樗鼈兛梢跃彺婧椭赜媒Y(jié)果。
- 如果你就是不想使用 gopls,這里列出了該插件支持的所有配置 https://github.com/golang/vscode-go/blob/master/docs/settings.md#detailed-list,在眾多配置中,如果某個(gè)配置有這樣的語(yǔ)句:Not applicable when using the language server ,表示 gopls 模式下該配置無(wú)效。
因此,我們不糾結(jié)之前的那些,只關(guān)注 gopls 相關(guān)的配置。(可以通過打開 Command Palette,搜索 Open Settings,直接打開配置文件)
啟用 gopls
打開 VSCode 配置界面,定位到 Extensions -> Go 中,找到 Use Language Server,勾選上。

對(duì)應(yīng)的配置是:"Go.useLanguageServer": true。如果你本地沒有安裝 gopls,會(huì)提示安裝。如果沒有提示,可以運(yùn)行 Go: Install/Update Tools 命令并選擇 gopls 進(jìn)行安裝。當(dāng) gopls 有更新時(shí),VSCode 會(huì)自動(dòng)更新。
配置 gopls
針對(duì) gopls 有三項(xiàng)配置:
- go.languageServerExperimentalFeatures:允許你禁用某些功能,一些實(shí)驗(yàn)性的特性;支持 diagnostics 和 documentLink,分別表示禁用診斷警告和禁用文檔鏈接;一般不需要配置;
- go.languageServerFlags:允許將 flags 傳遞給 gopls 進(jìn)程;這個(gè)需要先了解下 gopls 命令的 flags;
- gopls:目前 VSCode 不認(rèn),但起作用;
關(guān)于第 3 個(gè)配置 gopls,支持的配置列表參考:https://github.com/golang/tools/blob/master/gopls/doc/settings.md,比如:
- "gopls": {
- "usePlaceholders": true,
- "completeUnimported": true
- }
關(guān)于第 2 個(gè)配置,在后面專門介紹。一般我們只需要設(shè)置如下配置即可,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 涉及到的內(nèi)容很多,這里主要聊聊和 VSCode 編輯器相關(guān)的部分。
當(dāng)在 VSCode 中啟用 Use Language Server 時(shí),它會(huì)啟動(dòng)一個(gè) gopls 進(jìn)程,即它就是 LSP 的實(shí)現(xiàn),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
相關(guān)的子命令和 flags 不少。
默認(rèn)情況下,每次啟動(dòng)一個(gè) VSCode 窗口,gopls 進(jìn)程就會(huì)多一個(gè)。因?yàn)?gopls 需要維護(hù)大量的緩存,方便對(duì)編輯的源代碼進(jìn)行分析。因此,這種工作模式會(huì)導(dǎo)致 gopls 占用太多資源。
為了解決此類問題,gopls 支持一種新的模式,即啟動(dòng)一個(gè)單一的、持久的、共享的 gopls “守護(hù)進(jìn)程” 負(fù)責(zé)管理所有 gopls 會(huì)話。在這種模式下,編輯器的每一個(gè)窗口依然會(huì)啟動(dòng)一個(gè)新的 gopls,不過這個(gè) gopls 只是充當(dāng)轉(zhuǎn)發(fā)器,負(fù)責(zé)將 LSP 轉(zhuǎn)發(fā)到那個(gè)共享的 gopls 實(shí)例,并記錄相關(guān)指標(biāo)、日志和 rpc 跟蹤,因此這個(gè) gopls 占用資源很少。
要使用共享 gopls 實(shí)例,必須有一個(gè)守護(hù)進(jìn)程。你可以手動(dòng)啟動(dòng),不過更方便的是讓 gopls 轉(zhuǎn)發(fā)器進(jìn)程根據(jù)需要啟動(dòng)共享守護(hù)進(jìn)程。具體來(lái)說是使用 -remote=true 這個(gè) flag:
- gopls -remote=auto -logfile=auto -debug=:0 -remote.debug=:0 -rpc.trace
對(duì)于 VSCode 來(lái)說就是上文看到的如下配置:
- "go.languageServerFlags": [
- "-remote=auto", "-logfile=auto", "-debug=:0", "-rpc.trace",
- ]
這將導(dǎo)致該進(jìn)程在需要時(shí)自動(dòng)啟動(dòng) gopls 守護(hù)進(jìn)程,連接到它并轉(zhuǎn)發(fā) LSP。
注意,在沒有連接客戶端的情況下,共享 gopls 進(jìn)程將在一分鐘后自動(dòng)關(guān)閉。
關(guān)于共享 gopls 更多的內(nèi)容,可以查看 https://github.com/golang/tools/blob/master/gopls/doc/daemon.md 文檔。
另外上面配置中還有一個(gè)未提到:
- "go.trace.server": "verbose",
這用于在 Output 中輸出客戶端和 gopls Server 的通訊,方便調(diào)試,根據(jù)需要開啟。
此外,你應(yīng)該想到了,gopls 還支持遠(yuǎn)程開發(fā)。(上篇文章有人問,如果沒有網(wǎng)絡(luò)怎么辦。gopls 默認(rèn)是在本地啟動(dòng)服務(wù)的,所以不需要有網(wǎng)絡(luò),但這個(gè)遠(yuǎn)程開發(fā)就需要有網(wǎng)絡(luò)了)對(duì)遠(yuǎn)程開發(fā)感興趣的,可以查看文檔:https://github.com/golang/tools/blob/master/gopls/doc/vscode.md#vscode-remote-development-with-gopls。
體驗(yàn)下強(qiáng)大的 VSCode
到這里,一個(gè)強(qiáng)大的 Go 語(yǔ)言開發(fā)環(huán)境就搞定了。來(lái)體驗(yàn)一下吧。
以 studygolang 源碼為例,下載源碼:
- $ git clone https://github.com/studygolang/studygolang
打開 VSCode,選擇 File -> Open… 打開 studygolang 文件夾。打開 main.go 文件,分別嘗試如下功能:
- Code completion:輸入 fmt.Println 試試,看是否能正確提示;
- Hover:光標(biāo)懸停在某個(gè) symbol 上,看是否能正確出現(xiàn)文檔提示;
- Jump to definition:按住 Command(MacOS)或 CTRL(Linux 或 Windows) 點(diǎn)擊某個(gè) symbol,能否正確跳轉(zhuǎn)到定義;
- Find references:在某個(gè) symbol 上按 Shift + F12,能否正確顯示引用處;
- 。。。
不出意外,以上功能都應(yīng)該正常。
另外就是調(diào)試,在玩轉(zhuǎn) VSCode 系列教程第一篇已經(jīng)簡(jiǎn)單介紹了調(diào)試功能,這里不重復(fù)。
聊聊 Lint
Lint 是一個(gè)很有用的工具,各語(yǔ)言都會(huì)有。Go 語(yǔ)言也不例外,官方有一個(gè)工具 golint。然而,大家更喜歡第三方的 lint 工具,因?yàn)闊o(wú)論在性能、功能還是可定制性方面都更強(qiáng)大。VSCode 目前默認(rèn)使用 golint,但還支持另外三種 lint 工具:
- golangci-lint
- revive
- staticcheck
這三個(gè)工具都不錯(cuò),其中 staticcheck 還受到了 Google 和 Go 的贊助,因此有人建議廢棄官方的 golint,同時(shí)將 staticcheck 設(shè)為默認(rèn),當(dāng)然也有建議 revive 的,相關(guān) issue[1]。不過已經(jīng)確認(rèn)的是 golint 會(huì)凍結(jié)、廢棄:issue 38968[2]。
這三個(gè)工具,每一個(gè)都涉及到不少內(nèi)容。不過基本都是開箱即用,另外可以根據(jù)自己的需要進(jìn)行定制。我目前沒有切換,還是用的 golint,原因有 2:
- golint 目前基本夠用,沒有過多折騰這塊;
- golint 的輸出在 VSCode 的 PROBLEMS 窗口,而其他三個(gè)都在 OUTPUT 窗口。不喜歡;
期待哪天它們?nèi)齻€(gè)中的某個(gè)轉(zhuǎn)正吧。
和 GoLand 還有差距?
之前文章有人提到,VSCode 是否可以做到和 GoLand 類似的,將第三方依賴在 Explorer 顯示。好比 GoLand 的 External Libraries。
研究了一下,可以這么實(shí)現(xiàn)。
- 打開 VSCode,將某個(gè)項(xiàng)目加入,例如上面 studygolang;
- File -> Save Workspace As… 保存 Workspace,比如命名為 studygolang;
- 在 Explorer 中單擊右鍵,選擇 Add Folder to Workspace…,找到 module 第三方庫(kù)的路徑,一般是 $HOME/go/pkg/mod;
- 打開 studygolang.code-workspace,folders 改為:
- "folders": [
- { "name": "studygolang",
- "path": "."
- }, { "name": "External Libraries",
- "path": "../../../go/pkg/mod"
- }]
注意兩個(gè) name 的值。保存后,Explorer 變成這樣:

當(dāng)瀏覽代碼導(dǎo)航到依賴的庫(kù)時(shí),左邊 Explorer 也會(huì)定位到相應(yīng)的目錄。整體和 GoLand 還是類似的。
最后建議一個(gè) Go 項(xiàng)目一個(gè) VSCode 窗口,這樣不會(huì)亂。
總結(jié)
講了這么多,VSCode 打造為 Go 的開發(fā)環(huán)境,你還滿意嗎?看看我的 VSCode 界面:

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