大家好,我是煎魚。
我們從一開始寫 Go 程式碼和應用,就會被各種官方和民間教程,甚至 IDE 教導我們必須配一個 Gofmt 工具。他能夠格式化 Go 程式的程式碼。會使用製表符表示縮排,空白表示對齊。
這解決了程式設計師屆的老大難問題之一,程式碼格式上的規範問題。有效的提高了 Go 程式碼的閱讀的友好度和減少了同事間的 **。非常值得認可。
但有時候,還是會看到一些糟心的程式碼,總會覺得 Gofmt,還是格式化的不夠。
今天給大家分享我發現的一個更狠的工具:gofumpt,例子主要基於官方文件。
更強的格式化:gofumpt
Gofumpt 會執行比 gofmt 更嚴格的 Go 格式規範。同時確保向後相容。
該工具是 Go 1.21 的 gofmt 分支,需要 Go 1.20 或更高版本。它可以直接替代現有的 Go 程式碼格式化,也就是在 gofumpt 之後執行 gofmt 不會產生任何新的變化。
安裝命令:
$ go install mvdan.cc/gofumpt@latest
執行命令:
$ gofumpt -l -w .
main.go
再檢視對應被格式化的檔案就已經生效了。
以下是一些更具體的 gofmt 和 gofumpt 的區別例子。能夠很好的幫助大家識別其中的差異。
賦值運算子後無空行
原本由 gofmt 格式化後:
func foo() string {
foo :=
"腦子進煎魚了!"
return foo
}
改為 gofumpt 格式化後:
func foo() string {
foo := "腦子進煎魚了!"
return foo
}
函式體周圍無空行
原本由 gofmt 格式化後:
func foo() {
println("煎魚進腦子了!")
}
改為 gofumpt 格式化後:
func foo() {
println("煎魚進腦子了!")
}
函式應分隔 ) { ,縮排有助於提高可讀性
原本由 gofmt 格式化後:
func foo(s string,
i int) {
println("煎魚!!!")
}
// 使用空行會稍微好一些,但仍然不夠好
func bar(s string,
i int) {
println("煎魚!!!")
}
改為 gofumpt 格式化後:
func foo(s string,
i int,
) {
println("煎魚!!!")
}
func bar(s string,
i int,
) {
println("煎魚!!!")
}
程式碼塊中的單獨語句(或註釋)周圍沒有空行
原本由 gofmt 格式化後:
if err != nil {
return err
}
改為 gofumpt 格式化後:
if err != nil {
return err
}
簡單錯誤檢查前無空行
原本由 gofmt 格式化後:
foo, err := processFoo()
if err != nil {
return err
}
改為 gofumpt 格式化後:
foo, err := processFoo()
if err != nil {
return err
}
複合字面量應統一使用換行符
原本由 gofmt 格式化後:
var ints = []int{1, 2,
3, 4}
var matrix = [][]int{
{1},
{2}, {
3,
},
}
改為 gofumpt 格式化後:
var ints = []int{
1, 2,
3, 4,
}
var matrix = [][]int{
{1},
{2},
{
3,
},
}
空欄位列表應使用單行
原本由 gofmt 格式化後:
var V interface {
} = 3
type T struct {
}
func F(
)
改為 gofumpt 格式化後:
var V interface{} = 3
type T struct{}
func F()
標準庫匯入必須在頂部單獨分組
原本由 gofmt 格式化後:
import (
"foo.com/bar"
"io"
"io/ioutil"
)
改為 gofumpt 格式化後:
import (
"io"
"io/ioutil"
"foo.com/bar"
)
短 case 子句應占一行
原本由 gofmt 格式化後:
switch c {
case 'a', 'b',
'c', 'd':
}
改為 gofumpt 格式化後:
switch c {
case 'a', 'b', 'c', 'd':
}
多行頂層宣告必須用空行隔開
原本由 gofmt 格式化後:
func foo() {
println("煎魚!")
}
func bar() {
println("煎魚!")
}
改為 gofumpt 格式化後:
func foo() {
println("煎魚!")
}
func bar() {
println("煎魚!")
}
單個 var 宣告不應使用括號分組
原本由 gofmt 格式化後:
var (
foo = "煎魚!"
)
改為 gofumpt 格式化後:
var foo = "煎魚!"
連續的頂層宣告應歸為一組
原本由 gofmt 格式化後:
var nicer = "x"
var with = "y"
var alignment = "z"
改為 gofumpt 格式化後:
var (
nicer = "x"
with = "y"
alignment = "z"
)
簡單的 var 宣告語句應使用短賦值
原本由 gofmt 格式化後:
var s = "煎魚進腦子了"
改為 gofumpt 格式化後:
s := "煎魚進腦子了"
預設啟用 -s 程式碼簡化標記。
非 Go 指令的註釋應以空格開頭
原本由 gofmt 格式化後:
//go:noinline
//Foo is awesome.
func Foo() {}
改為 gofumpt 格式化後:
//go:noinline
// Foo is awesome.
func Foo() {}
VSCode 配置
可以直接在 IDE 中進行配置。例如 VSCode,可以配置對應的 settings.json 為如下:
{
"go.useLanguageServer": true,
"gopls": {
"formatting.gofumpt": true,
},
}
就可以直接在 Go 應用中用起來了。
總結
之前我有一個朋友,接手了一個老專案。那位同學,幾乎沒有什麼程式碼規範的風格。全靠 gofmt 來幫他格式化。
但你們也看到,gofmt 只做了最基本的。這種時候如果有更嚴格的 Go 程式碼格式化工具 gofumpt 是非常不錯的。(也需要引導這位同學,但容易撕逼)
像是前面提到的 “多行頂層宣告必須用空行隔開” 是非常有價值的。我是真的見過一大坨不加空行都擠一起的。看起來非常難受。
希望這個更嚴格的 gofumpt,對大家格式化 Go 程式碼能有所幫助!
文章持續更新,可以微信搜【腦子進煎魚了】閱讀,本文 GitHub github.com/eddycjy/blog 已收錄,學習 Go 語言可以看 Go 學習地圖和路線,歡迎 Star 催更。