Go代码断行规则

本文详细介绍了Go语言中的分号插入规则,包括何时会自动插入分号,以及由此产生的自增自减运算和选择器的断行限制。同时,文章也讨论了逗号的使用规则,指出在某些情况下,逗号是必须的,而编译器不会自动插入。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.分号插入规则

自动插入分号的规则是什么呢?Go白皮书是这样描述的

1.在Go代码中,注释除外,如果一个代码行的最后一个语法词段(token)为下列所示之一,则一个分号将自动插入在此字段后(即行尾):

  • 一个标识符;
  • 一个整数、浮点数、虚部、码点或者字符串字面量表示形式;
  • 这几个跳转关键字之一:breakcontinuefallthroughreturn
  • 自增运算符++或者自减运算符--
  • 一个右括号:)]}

2.为了允许一条复杂语句完全显示在一个代码行中,分号可能被插入在一个右小括号)或者右大括号}之前。

第二条规则允许我们写出如下的代码:

import (_ "math";"fmt")
var (a int; b string)
const (M = iota;N)
type (MyInt int;T struct{x bool;y int32})
type I interface{m1(int); m2() string}
func f() {fmt,Println("a");panic(nil)}

编译器在编译时刻将自动插入所需的分号,如下所示:

var (a int; b string;);
const (M = iota; N;);
type (MyInt int;T struct{x bool;y int32;};);
type I interface{m1(int); m2() string;};
func f() {fmt,Println("a");panic(nil);};

分号自动插入规则导致的一个结果是:自增和自减运算必须呈现为单独的语句,它们不能被当作表达式使用。比如下面的代码是编译不通过的:

func f() {
	a := 0
	fmt.Println(a++)
	fmt.Println(a--)
}

上面的代码编译不通过的原因是它等价于下面的代码:

func f() {
	a := 0;
	fmt.Println(a++;);
	fmt.Println(a--;);
}

分号自动插入规则导致的另一个结果是:我们不能在选择器中的句点.之前断行。在选择器中的句点之后断行是允许的。比如:

anObject.
	MethodA().
	MethodB().
	MethodC()

而下面这样是非法的:

anObject
	.MethodA()
	.MethodB()
	.MethodC()

此段代码是非法的原因是,被编译器将自动在每个右小括号)后面插入一个分号,如下所示:

anObject;
	.MethodA();
	.MethodB();
	.MethodC();

需要注意的是switch-case语法断行后的区别:

func alwaysFalse() bool { return false }

func main() {
	switch alwaysFalse() 
	{
	case true:fmt.Println("true")
	case false:fmt.Println("fase")
	}
}

上述的switch-case代码块输出的是true,而不是flase。此代码块和下面这个是不同的:

switch alwaysFalse() {
	case true:fmt.Println("true")
	case false:fmt.Println("fase")
}

如果我们使用go fmt命令格式化前者,一个分号将自动添加到alwaysFalse()函数调用之后,如下所示:

switch alwaysFalse();
{
case true:fmt.Println("true")
case false:fmt.Println("fase")
}

插入分号后,此代码块将和下者等价:

switch alwaysFalse();true {
case true:fmt.Println("true")
case false:fmt.Println("false")
}

这就是它为什么输出true的原因。常使用go fmtgo vet命令来格式化和发现可能的逻辑错误是一个好习惯。

下面是一个很少见的情形,此情形中所示的代码看上去是合法的,但是实际上是编译不通过的。

func f(x int) {
	switch x {
	case 1:
	{
		goto A
		A:	// 这里编译没问题
	}
	case 2:
		goto B
		B:	// syntax error:跳转标签后缺少语句
	case 3:
		goto C
		C:	// 这里编译没问题
	}
}

编译错误信息表明跳转标签的声明之后必须跟一条语句。但是,看上去,上例中的三个标签声明没什么不同,它们都没有跟随一条语句。那为什么只有B:标签声明是不合法的呢?原因是,根据上述第二条分号自动插入规则,编译器将在A:C:标签声明之后的右大括号}字符之前插入一个分号,如下所示:

func f(x int) {
	switch x {
	case 1:
	{
		goto A
		A:	
	;}	// 一个分号插入到了这里
	case 2:
		goto B
		B:	// syntax error:跳转标签后缺少语句
	case 3:
		goto C
		C:	
	;}	// 一个分号插入到了这里
}

一个单独的分号实际上表示一条空语句。这就是为什么A:C:标签声明之后确实跟随了一条语句的原因,所以它们是合法的。而B:标签声明跟随的case 0:不是一条语句,所以它是不合法的。我们可以在B:标签声明之后手动插入一个分号使之变得合法。

2.逗号,从不会被自动插入

一些包含多个类似项目的语法形式多用逗号,来作为这些项目之间的分割符,比如组合字面值和函数参数列表等。在这样的一个语法形式中,最后一个项目总可以跟一个可选的逗号。如果此逗号为它所在代码行的最后一个有效字符,则此逗号是必需的;否则,此逗号可以省略。编译器在任何情况下都不会自动插入逗号。

比如,下面的代码是合法的:

func f1(a int,b string,) (x bool,y int,) {
	return true,789
}

var f2 func (a int,b string) (x bool,y int)
var f3 func (a int,b string,	// 最后一个逗号是必须的
) (x bool, y int,	// 最后一个逗号是必须的
)

var _ = []int{2,3,5,7,9,}	// 最后一个逗号是可选的
var _ = []int{2,3,5,7,9,	// 最后一个逗号是必需的
}

var _,_ = f1(123,"Go",)		// 最后一个逗号是可
var _,_ = f1(123,"Go",		// 最后一个逗号是必
)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值