Golang中的控制结构_Golang条件语句与循环语法

1次阅读

gowhile/do-while和三元运算符iffor可省括号但花括号不可省,且if支持初始化语句(如if err:=f(); err!=nil{…}),变量作用域限于对应分支;for是唯一循环结构,有类C、while、无限循环三种形式。

Golang中的控制结构_Golang条件语句与循环语法

Go 里没有 while、do-while,也不支持三元运算符;iffor 的括号可以省,但花括号不能省——这是写错最多的地方。

Go 的 if 语句必须带花括号,且支持初始化语句

常见错误是照搬其他语言习惯,写成 if x > 0 { ... } else { ... } 看似正常,但一旦漏掉花括号(比如只有一行想省略),编译直接报错:syntax Error: unexpected else, expecting }

Go 要求所有分支都必须用花括号包裹,哪怕只有一行。另外,if 后可紧跟初始化语句,变量作用域仅限该 if 块:

if err := someFunc(); err != nil {     log.Fatal(err) } else if n := len(data); n == 0 {     fmt.Println("empty") }
  • 初始化语句和条件表达式之间用分号隔开,不是逗号
  • errn 在各自分支外不可访问,避免污染外层作用域
  • 不支持 if x > 0 ? a : b 这类三元写法,得用完整 if/else

for 是 Go 唯一的循环结构,三种写法对应不同场景

Go 没有 whiledo-while,所有循环都靠 for 实现。它有三种合法形式,本质都是同一语法糖的不同展开:

立即学习go语言免费学习笔记(深入)”;

// 1. 类 C 风格(带初始化、条件、后置) for i := 0; i < 5; i++ {     fmt.Println(i) }  // 2. 类 while 风格(只有条件) for count < 10 {     count++ }  // 3. 无限循环(等价于 for ;;) for {     select {     case msg := <-ch:         handle(msg)     case <-done:         break     } }
  • 第二种写法容易被误认为“缺少分号就报错”,其实只要条件表达式存在,就合法
  • 第三种常用于 goroutine 中配合 select,但记得用 break 退出时要加标签才能跳出多层嵌套
  • 遍历切片/映射/通道请用 range,不是 for i = 0; i ——后者在并发中可能 panic,且无法感知底层变化

switch 默认自动 break,且支持类型断言和条件表达式

Go 的 switch 不会穿透(fallthrough 需显式写出),而且 case 可以是任意可比较类型或布尔表达式:

switch v := x.(type) { case int:     fmt.Printf("int: %d", v) case string:     fmt.Printf("string: %s", v) default:     fmt.Printf("unknown type: %T", v) }
  • 类型开关(x.(type))只能用于接口类型,且 v 是具体值,不是类型名
  • 普通 switch 也可以写条件:switch { case x > 0 && y ,此时 case 后是布尔表达式,不需要 switch 后跟值
  • 想穿透必须写 fallthrough,且它必须是 case 最后一条语句,后面不能有 return 或 break

控制流中的常见陷阱:作用域、空分支、defer 执行时机

这些细节不报错,但行为常和预期不符:

  • iffor 内部定义的变量,在外部不可见;但若在顶层作用域多次用 := 声明同名变量(如循环内),会报 no new variables on left side of :=
  • 空分支(如 if cond {} else {})合法,但容易掩盖逻辑缺失,建议用 panic 或日志占位
  • defer 在函数返回前执行,不是块结束时——这意味着 for 循环里的 defer 会在整个函数结束才批量触发,不是每次迭代都执行

最易忽略的是 range 遍历时对切片元素取地址:所有迭代共享同一个变量地址,导致最后全指向最后一个元素。要存地址,得在循环内显式拷贝:val := val; ptr := &val

text=ZqhQzanResources