Skip to content

第03章 面试题精选 —— 流程控制


★ 基础题

Q1:Go 的 for 循环和 C/Java 的 for 循环有什么不同?

  1. 没有括号for i := 0; i < 10; i++ 比 C 少了 ()
  2. 没有 while/do-while:所有循环都用 for
  3. for range 是 Go 独有的语法糖
  4. 大括号必须紧跟同行for { ... } 不能写成下一行

Q2:Go 的 switch 和 C 的 switch 有什么不同?

C/JavaGo
默认行为自动穿透(fall-through)不穿透
显式穿透不写 breakfallthrough
case 类型整数/字符/枚举任意类型,包括字符串
多值匹配写多个 case一个 case 可写多个值 case 1, 3, 5:
无条件 switchswitch { case cond: ... }
类型 switchswitch x.(type) { case int: ... }

Q3:以下代码输出什么?

go
for i := 0; i < 5; i++ {
    if i == 3 { break }
    if i == 1 { continue }
    fmt.Println(i)
}

02

  • i=0 打印
  • i=1 continue 跳过
  • i=2 打印
  • i=3 break 退出

Q4:用 for range 遍历切片时,索引和值的类型分别是什么?

go
nums := []int{10, 20, 30}
for i, v := range nums {
    // i 是 int,v 是 nums 的元素类型 int
}
  • 索引 i 永远是 int
  • v 是切片元素类型

⚠️ 遍历 map 时索引是 key、值是 value,且顺序随机


Q5:下面的代码有问题吗?

go
nums := []int{1, 2, 3}
for _, v := range nums {
    v *= 2
}
fmt.Println(nums)

nums 不会被修改,输出 [1 2 3]

原因v元素的副本,修改副本不影响原切片。

要修改原切片:

go
for i := range nums {
    nums[i] *= 2
}

★★ 进阶题

Q6:for range 在 Go 1.22 之前有什么著名的 bug?

go
funcs := []func(){}
for _, v := range []int{1, 2, 3} {
    funcs = append(funcs, func() { fmt.Println(v) })
}
for _, f := range funcs {
    f()
}

Go 1.22 之前:输出 3 3 3(三个闭包共享同一个 v
Go 1.22+:输出 1 2 3(每次循环 v 都是新变量)

这是 Go 多年来最大的"隐式坑",1.22 默认修复。


Q7:switch x.(type) 是什么?什么时候用?

类型 switch(type switch),用来判断接口变量的实际动态类型

go
func describe(x interface{}) {
    switch v := x.(type) {
    case nil:
        fmt.Println("nil")
    case int, int32, int64:
        fmt.Println("整数族", v)
    case string:
        fmt.Println("字符串", v)
    default:
        fmt.Printf("未知 %T\n", v)
    }
}

注意case int, int32, int64: 这种多类型写法时,v 是接口类型,不是具体类型。


Q8:Go 中 if 后面能不能跟 ; 之外的 init 语句?

只能跟一个简单语句(SimpleStmt),常见的有:

  • 短变量声明:if a := f(); a > 0 { ... }
  • 表达式:if g(); cond { ... }(很少用)

不能跟:varfor、循环语句、return 等。


Q9:写一段代码:判断一个数是不是素数。

go
func isPrime(n int) bool {
    if n < 2 { return false }
    for i := 2; i*i <= n; i++ {
        if n%i == 0 { return false }
    }
    return true
}

关键点:循环条件是 i*i <= n,不需要遍历到 n


Q10:用 Go 写"打印九九乘法表"。

go
for i := 1; i <= 9; i++ {
    for j := 1; j <= i; j++ {
        fmt.Printf("%d×%d=%-2d  ", j, i, i*j)
    }
    fmt.Println()
}

考察点:嵌套循环 + 格式化输出 + 控制对齐。


★★★ 深度题

Q11:Go 为什么没有三元运算符 ? :

官方理由:保持语言简洁性可读性? : 嵌套起来很难读,Go 推荐显式的 if-else:

go
// Java: int max = a > b ? a : b;
// Go:
var max int
if a > b { max = a } else { max = b }

Q12:循环变量的逃逸问题

go
for i := 0; i < 3; i++ {
    go func() {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(i)   // Go 1.22 前打印 3 3 3
    }()
}

Go 1.21 及之前:3 个 goroutine 共享同一个 i,因为 i 在循环外只声明一次。
Go 1.22+:每次循环 i 都是新变量,输出 0 1 2(顺序不定)。


📌 速记口诀

"if 不要括号;for 一统天下;switch 不穿透;range 取副本"


🎯 自测练习

  1. 写一个程序:从 1 数到 100,但跳过所有含 7 的数字(如 7、17、27...、70-79)
  2. 写九九乘法表
  3. 用 switch 实现一个"猜大小"游戏的判断逻辑
  4. for range 遍历一个 map 并按 key 排序输出(提示:先把 key 收到 slice,再排序)

完成后进入第04章 🚀