如何在 Golang 破解长长的代码行?

来自 Python,我不习惯看到超过80列的代码行。 所以当我遇到这个:

err := database.QueryRow("select * from users where user_id=?", id).Scan(&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email)

我试图打破它

err := database.QueryRow("select * from users where user_id=?", id) \
.Scan(&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email)

但我明白

 syntax error: unexpected \

我还试着用回车键打破这条线,并在结尾处加上一个分号:

err := database.QueryRow("select * from users where user_id=?", id)
.Scan(&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email);

但是我又得到了:

syntax error: unexpected .

所以我想知道高朗格法是怎么做到的?

89562 次浏览

最简单的方法是将操作符(.)保留在第一行。

在许多 Python 样式指南中也不鼓励使用 \行的延续,如果在 go 和 python 之间来回移动,可以用括号来包装整个表达式,因为这种技术在两种语言中都适用。

这是风格问题,但我喜欢:

err := database.QueryRow(
"select * from users where user_id=?", id,
).Scan(
&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email,
)

首先是一些背景资料。Go 的正式语法在许多结果中使用分号 ";"作为结束符,但 Go 程序可能会省略其中的大部分(它们应该有一个更清晰、易读的源代码; gofmt还删除了不必要的分号)。

该规范列出了确切的规则

形式语法在许多结果中使用分号“ ;”作为终止符。Go 程序可以使用以下两个规则省略大部分分号:

  1. 当输入被分解成标记时,如果分号被分解成标记,那么一个分号会自动插入到标记流中,紧接在一行的最后一个标记之后

  2. 为了允许复杂语句占据一行,可以在结尾“)”或“}”前省略分号。

因此,如果在括号 )之后插入换行符,则会自动插入分号 ;,因此下一行不会被视为前一行的延续。这就是在您的例子中发生的情况,因此以 .Scan(&ReadUser.ID,...开始的下一行将给出一个编译时错误,因为 本身(没有前一行)的这个位置是一个编译时错误: syntax error: unexpected .

所以你可以在任何不与上面 1.点所列出的规则相冲突的地方断开你的线。

通常你可以在逗号 ,之后,在 打开括号之后,例如 ([{之后,或者在一个点 .之后,这个点 .可能引用一个字段或方法的某个值。你也可以在二进制运算符(那些需要两个操作数的运算符)后面换行,例如:

i := 1 +
2
fmt.Println(i) // Prints 3

这里值得注意的一点是,如果你有一个结构或片或映射文字列出初始值,并且你想在列出最后一个值之后换行,你必须放置一个强制性的逗号 ,,即使这是最后一个值,不会有更多,例如:

s := []int {
1, 2, 3,
4, 5, 6,  // Note it ends with a comma
}

这是为了符合分号规则,也是为了你可以重新排列和添加新的行而不必去添加/删除最后的逗号; 例如,你可以简单地交换2行而不必删除和添加一个新的逗号:

s := []int {
4, 5, 6,
1, 2, 3,
}

列出函数调用的参数时也是如此:

fmt.Println("first",
"second",
"third",       // Note it ends with a comma
)

如前所述,这是一个风格偏好的问题。我知道围棋的创造者们根据他们的经验建议了一种围棋风格,我从中学到了一些东西,但也从我的经验中保留了一些我自己的风格。

下面是我将如何格式化它:

err := database.
QueryRow("select * from users where user_id=?", id).
Scan(
&ReadUser.ID,
&ReadUser.Name,
&ReadUser.First,
&ReadUser.Last,
&ReadUser.Email,
)

高朗格方法是什么?

一个自动化的解决方案。不幸的是,gofmt没有涵盖这种情况,所以您可以使用 Https://github.com/segmentio/golines

通过

go install github.com/segmentio/golines@latest

那就快跑

golines -w -m 80 .

-w意味着就地进行更改(默认打印到 stdout)

-m是最大列长