Go 更强的代码洁癖,可以把 gofmt 给换了!

大家好,我是煎鱼。

我们从一开始写 Go 代码和应用,就会被各种官方和民间教程,甚至 IDE 教导我们必须配一个 Gofmt 工具。他能够格式化 Go 程序的代码。会使用制表符表示缩进,空白表示对齐。

这解决了程序员届的老大难问题之一,代码格式上的规范问题。有效的提高了 Go 代码的阅读的友好度和减少了同事间的 ****。非常值得认可。

但有时候,还是会看到一些糟心的代码,总会觉得 Gofmt,还是格式化的不够。

今天给大家分享我发现的一个更狠的工具:gofumpt,例子主要基于官方文档。

更强的格式化:gofumpt

Gofumpt 会执行比 gofmt 更严格的 Go 格式规范。同时确保向后兼容。

该工具是 Go 1.21 的 gofmt 分支,需要 Go 1.20 或更高版本。它可以直接替代现有的 Go 代码格式化,也就是在 gofumpt 之后运行 gofmt 不会产生任何新的变化。

安装命令:

shell 复制代码
$ go install mvdan.cc/gofumpt@latest

执行命令:

shell 复制代码
$ gofumpt -l -w .
main.go

再查看对应被格式化的文件就已经生效了。

以下是一些更具体的 gofmt 和 gofumpt 的区别例子。能够很好的帮助大家识别其中的差异。

赋值运算符后无空行

原本由 gofmt 格式化后:

go 复制代码
func foo() string {
	foo :=
		"脑子进煎鱼了!"
	return foo
}

改为 gofumpt 格式化后:

go 复制代码
func foo() string {
	foo := "脑子进煎鱼了!"
	return foo
}

函数体周围无空行

原本由 gofmt 格式化后:

go 复制代码
func foo() {

	println("煎鱼进脑子了!")

}

改为 gofumpt 格式化后:

go 复制代码
func foo() {
	println("煎鱼进脑子了!")
}

函数应分隔 ) { ,缩进有助于提高可读性

原本由 gofmt 格式化后:

go 复制代码
func foo(s string,
	i int) {
	println("煎鱼!!!")
}

// 使用空行会稍微好一些,但仍然不够好
func bar(s string,
	i int) {

	println("煎鱼!!!")
}

改为 gofumpt 格式化后:

go 复制代码
func foo(s string,
	i int,
) {
	println("煎鱼!!!")
}

func bar(s string,
	i int,
) {
	println("煎鱼!!!")
}

代码块中的单独语句(或注释)周围没有空行

原本由 gofmt 格式化后:

go 复制代码
if err != nil {

	return err
}

改为 gofumpt 格式化后:

go 复制代码
if err != nil {
	return err
}

简单错误检查前无空行

原本由 gofmt 格式化后:

go 复制代码
foo, err := processFoo()

if err != nil {
	return err
}

改为 gofumpt 格式化后:

go 复制代码
foo, err := processFoo()
if err != nil {
	return err
}

复合字面量应统一使用换行符

原本由 gofmt 格式化后:

go 复制代码
var ints = []int{1, 2,
	3, 4}

var matrix = [][]int{
	{1},
	{2}, {
		3,
	},
}

改为 gofumpt 格式化后:

go 复制代码
var ints = []int{
	1, 2,
	3, 4,
}

var matrix = [][]int{
	{1},
	{2},
	{
		3,
	},
}

空字段列表应使用单行

原本由 gofmt 格式化后:

go 复制代码
var V interface {
} = 3

type T struct {
}

func F(
)

改为 gofumpt 格式化后:

go 复制代码
var V interface{} = 3

type T struct{}

func F()

标准库导入必须在顶部单独分组

原本由 gofmt 格式化后:

go 复制代码
import (
	"foo.com/bar"

	"io"

	"io/ioutil"
)

改为 gofumpt 格式化后:

go 复制代码
import (
	"io"
	"io/ioutil"

	"foo.com/bar"
)

短 case 子句应占一行

原本由 gofmt 格式化后:

go 复制代码
switch c {
case 'a', 'b',
	'c', 'd':
}

改为 gofumpt 格式化后:

go 复制代码
switch c {
case 'a', 'b', 'c', 'd':
}

多行顶层声明必须用空行隔开

原本由 gofmt 格式化后:

go 复制代码
func foo() {
	println("煎鱼!")
}
func bar() {
	println("煎鱼!")
}

改为 gofumpt 格式化后:

go 复制代码
func foo() {
	println("煎鱼!")
}

func bar() {
	println("煎鱼!")
}

单个 var 声明不应使用括号分组

原本由 gofmt 格式化后:

go 复制代码
var (
	foo = "煎鱼!"
)

改为 gofumpt 格式化后:

go 复制代码
var foo = "煎鱼!"

连续的顶层声明应归为一组

原本由 gofmt 格式化后:

go 复制代码
var nicer = "x"
var with = "y"
var alignment = "z"

改为 gofumpt 格式化后:

go 复制代码
var (
	nicer     = "x"
	with      = "y"
	alignment = "z"
)

简单的 var 声明语句应使用短赋值

原本由 gofmt 格式化后:

go 复制代码
var s = "煎鱼进脑子了"

改为 gofumpt 格式化后:

go 复制代码
s := "煎鱼进脑子了"

默认启用 -s 代码简化标记。

非 Go 指令的注释应以空格开头

原本由 gofmt 格式化后:

csharp 复制代码
//go:noinline

//Foo is awesome.
func Foo() {}

改为 gofumpt 格式化后:

go 复制代码
//go:noinline

// Foo is awesome.
func Foo() {}

VSCode 配置

可以直接在 IDE 中进行配置。例如 VSCode,可以配置对应的 settings.json 为如下:

json 复制代码
{
    "go.useLanguageServer": true,
    "gopls": {
        "formatting.gofumpt": true,
    },
}

就可以直接在 Go 应用中用起来了。

总结

之前我有一个朋友,接手了一个老项目。那位同学,几乎没有什么代码规范的风格。全靠 gofmt 来帮他格式化。

但你们也看到,gofmt 只做了最基本的。这种时候如果有更严格的 Go 代码格式化工具 gofumpt 是非常不错的。(也需要引导这位同学,但容易撕逼)

像是前面提到的 "多行顶层声明必须用空行隔开" 是非常有价值的。我是真的见过一大坨不加空行都挤一起的。看起来非常难受。

希望这个更严格的 gofumpt,对大家格式化 Go 代码能有所帮助!

文章持续更新,可以微信搜【脑子进煎鱼了】阅读,本文 GitHub github.com/eddycjy/blo... 已收录,学习 Go 语言可以看 Go 学习地图和路线,欢迎 Star 催更。

推荐阅读

相关推荐
DemonAvenger17 小时前
深入剖析 sync.Once:实现原理、应用场景与实战经验
分布式·架构·go
一个热爱生活的普通人2 天前
Go语言中 Mutex 的实现原理
后端·go
孔令飞2 天前
关于 LLMOPS 的一些粗浅思考
人工智能·云原生·go
小戴同学2 天前
实时系统降低延时的利器
后端·性能优化·go
Golang菜鸟2 天前
golang中的组合多态
后端·go
Serverless社区3 天前
函数计算支持热门 MCP Server 一键部署
go
Wo3Shi4七3 天前
二叉树数组表示
数据结构·后端·go
网络研究院3 天前
您需要了解的有关 Go、Rust 和 Zig 的信息
开发语言·rust·go·功能·发展·zig
27669582923 天前
拼多多 anti-token unidbg 分析
java·python·go·拼多多·pdd·pxx·anti-token
程序员爱钓鱼3 天前
Go 语言邮件发送完全指南:轻松实现邮件通知功能
后端·go·排序算法