Menu

Golang if else:语法、初始化语句与 if err != nil

Go 中 if、else if 和 else 的用法:条件不加圆括号,花括号必不可少,带初始化语句的 if 及其作用域,if err != nil 惯用法,以及用提前返回代替深层嵌套。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

Go 的 if 条件两边不加圆括号,花括号必不可少,而且可以先写一条简短语句,声明只在这个 if 内有效的变量。

条件从上往下依次检查,执行第一个为真的分支。else if 和 else 都是可选的。

语法规则

有三条规则与 C、Java 和 JavaScript 不同:

  1. 条件两边不加圆括号。if (x > 5) 能编译通过,但 gofmt 会去掉这对圆括号。
  2. 花括号必不可少,哪怕只有一条语句。不存在不带花括号的 if x > 5 return。
  3. else 要和右花括号写在同一行。Go 会在行尾的 } 后插入分号,所以下面的写法会失败:
if x > 5 {
	fmt.Println("big")
}
else {
	fmt.Println("small")
}
syntax error: unexpected keyword else, expected }

把 } else { 写在同一行。

条件必须是 bool 类型。Go 不会把 0、"" 或 nil 当作 false,所以 if count {} 和 if name {} 都无法编译。要显式比较:if count > 0、if name != ""、if user != nil。

用 &&(与)、||(或)和 !(非)组合条件。&& 和 || 都会短路求值,所以 nil 检查是安全的:

if user != nil && user.IsAdmin() {
	// user.IsAdmin() is only called when user is not nil
}

带初始化语句的 if

if 可以在条件之前先执行一条简短语句,两者用分号隔开。在其中声明的变量在这个 if 的每个分支里都可见,在 if 之后则不可见:

这种写法让临时变量不会污染外层作用域。它在 map 查找(v, ok := m[k])、类型断言(s, ok := v.(string))和错误处理中随处可见。

反过来说:如果你需要在 if 之后使用这个值,就在 if 之前声明它。一个常见错误是把结果放进初始化语句,然后又想在下面使用它。

if err != nil 惯用法

可能失败的函数会把 error 放在最后一个返回值。立即检查它,处理或返回它,然后让正常流程不缩进地继续往下走:

注意,if err != nil { return ... } 之后没有 else。Go 的风格是处理错误、返回,并让正常流程保持在最左侧。错误处理页面会讲解如何包装错误以及检查错误类型。

用提前返回代替嵌套

层层嵌套的 if 块很难读。把条件反过来并提前返回,每个检查就成了一道守卫:

// Nested
func canCheckout(u *User, cart *Cart) bool {
	if u != nil {
		if u.Verified {
			if len(cart.Items) > 0 {
				return true
			}
		}
	}
	return false
}

// Guards
func canCheckout(u *User, cart *Cart) bool {
	if u == nil || !u.Verified {
		return false
	}
	if len(cart.Items) == 0 {
		return false
	}
	return true
}

Go 程序员把这叫作让正常路径靠左对齐。revive 等 linter 会标记以 return 结尾的代码块之后的 else,因为这个 else 只是白白增加了缩进。

if/else 与 switch

一长串用同一个值去比较多种情况的 else if,改写成 switch 会更好读。不带表达式的 switch 可以代替由任意条件组成的 if/else if 链:

switch {
case score >= 90:
	return "A"
case score >= 80:
	return "B"
default:
	return "F"
}

一两个分支用 if,三个或更多分支就用 switch。

没有三元运算符

Go 没有 cond ? a : b。用 if 来赋值:

label := "odd"
if n%2 == 0 {
	label = "even"
}

三元运算符页面解释了原因,并介绍了替代写法。

常见错误

  • 用 := 造成变量遮蔽。 if x, err := f(); err == nil { ... } 声明了一个只属于这个 if 的新 x,外层的 x 不会被更新。
  • 在条件里赋值。 if x = 5 {} 是编译错误(cannot use assignment x = 5 as value),而不是像 C 语言那样悄悄埋下 bug。请使用 ==。
  • 用 == 比较浮点数。 对计算得到的值,if total == 0.3 会失败。要在一个容差范围内比较。
  • 检查了错误的 error。 在 a, err := f() 和 b, err := g() 之后,确保每个 if err != nil 都紧跟在对应的调用后面。

常见问题

Go 语言怎么写 if else?

条件两边不加圆括号,而且花括号必不可少:

if x > 10 {
	fmt.Println("big")
} else if x > 5 {
	fmt.Println("medium")
} else {
	fmt.Println("small")
}

else 必须和上一个代码块的右花括号写在同一行。

Go 中带初始化语句的 if 是什么?

就是在条件前面加一条简短语句,用分号隔开:if n, err := strconv.Atoi(s); err != nil { ... }。在这里声明的变量只存在于这个 if 及其 else if 和 else 分支中,不会泄漏到函数的其余部分。

Go 里可以写单行 if 吗?

不加花括号不行。if ok return 和 if (ok) x = 1; 都是语法错误。最短的写法是 if ok { return },而 gofmt 会把语句体放到单独一行。Go 也没有三元运算符,所以要根据条件取值,就需要 if/else 或一个小的辅助函数。

为什么 Go 到处都是 if err != nil?

Go 没有异常。可能失败的函数会把一个 error 作为最后一个返回值,调用者立即用 if err != nil 检查它。这种重复换来的是:每个可能失败的地方都在出错的位置清清楚楚地写着。

Coddy 编程语言插图

和 Coddy 一起学编程

开始