Go 语言面试题
- 并发
一句话:go 关键字启动 goroutine,channel 做 CSP 通信。
go f() // 启动
ch <- v // 发送
v := <-ch // 接收
- error 处理
一句话:最后一个返回值约定为error
,if err != nil
立刻处理;堆栈用fmt.Errorf("%w", err)
或github.com/pkg/errors
。
if err != nil {return fmt.Errorf("wrap: %w", err)
}
- 接口
一句话:隐式实现,只要方法集匹配就算实现。
type Foo interface{ Bar() }
type T struct{}
func (T) Bar() {} // T 实现了 Foo
- init
一句话:包级func init()
,在main
之前按 import 深度顺序执行;常用来做一次性初始化。
func init() { rand.Seed(time.Now().Unix()) }
-
声明变量
一句话:三种——var x int
、x := 1
、var (a=1 b=2)
。 -
基础类型
一句话:数字、字符串、bool、派生类型(array、slice、map、struct、pointer、func、chan、interface)。 -
两个 nil 是否相等
一句话:类型相同时可比较;interface 与具体类型 nil 不相等是常见坑。
var p *int = nil
var i interface{} = p
fmt.Println(i == nil) // false
- 常量
const Pi = 3.14
- 方法
一句话:在 func 名前加接收者(t T)
或(t *T)
。
func (p Person) Name() string { return p.name }
- loop
for i:=0; i<10; i++ {} // 三段式
for {} // while(true)
-
数组
固定长度:var a [5]int
;自动长度:a := [...]int{1,2,3}
。 -
切片
动态数组,三字段结构:ptr,len,cap
。
s := []int{1,2,3}
s = append(s, 4) // 记得接收返回值
- map
m := make(map[string]int)
m["age"] = 30
- map 遍历/取值/删除
for k, v := range m { ... }
v := m["key"]
delete(m, "key")
-
遍历时删除
一句话:官方未定义行为,先收集 key 再删或复制新 map。 -
不能当 key 的类型
slice、map、func、含这些字段的 struct。 -
指针
p := &x
fmt.Println(*p)
传指针可修改原值;传值是拷贝。
- channel
ch := make(chan int) // 无缓冲
buf := make(chan int, 3) // 有缓冲
-
无缓冲 vs 有缓冲
无缓冲:收发同步阻塞;有缓冲:缓冲未满则异步,满后阻塞。 -
读 channel
v := <-ch
-
关闭 channel
close(ch)
v, ok := <-ch // ok==false 表示已关闭
-
goroutine 与停止
启动:go f()
;停止:通过context.WithCancel
或chan struct{}
通知退出。 -
公开/私有
首字母大写导出,小写包内私有。 -
包循环依赖
一句话:Go 禁止;把公共接口提到第三个包或合并包。 -
包 vs 模块
包 = 目录下 .go 文件;模块 = 带 go.mod 的若干包集合,带版本号。 -
编译可执行
go build -o app main.go
-
nil slice vs 空 slice
nil:var s []int
(lencap0,未分配底层数组);空:s := []int{}
(len==0,cap>=0,已分配)。 -
append
s = append(s, 1, 2, 3)
- nil map vs 空 map
nil:var m map[K]V
(未初始化,直接赋值 panic);空:m = make(map[K]V)
(可用)。
面试小贴士
• 问“slice 和数组区别”,先答“长度固定 vs 动态”,再补“底层结构 len/cap”。
• 问“goroutine 泄露”,答“忘记接收导致 channel 阻塞”或“没有 cancel context”。
• 问“map 是否并发安全”,答“不安全,需加锁或用 sync.Map”。