下面这些是 Go 语言本身的规则(编译器/运行时强制,或官方强烈约定)。
1. 包与可见性(你已经知道)
- 一个目录 = 一个包,包名通常等于目录名。
- 首字母大写导出,小写仅本包。
package main+func main()才是可执行入口。- 只能
import别的包,不能 import 单个文件;同包文件互相可见、不用 import。
2. 编译与依赖
- 模块以
go.mod的module名为 import 前缀(本仓库是audit-review)。 - 循环 import 禁止:A import B、B 再 import A 会编译失败。
- 未使用的 import、未使用的局部变量是 编译错误 (
_可丢掉不想用的值)。 - 没有隐式类型转换:
int32和int64必须显式转。
3. 零值与指针
- 变量声明后就是零值:
0、""、nil、false,没有「未初始化」的垃圾值。 nil指针解引用会 panic。new(T)/&T{}得到*T;方法接收者常用指针,避免拷贝、允许修改。
4. 错误处理
- 没有异常体系当主路径;约定返回
(result, error)。 error == nil才算成功;忽略 error 是合法语法,但是坏习惯。panic只用于真正不可恢复(配置都扫不进来);recover一般只在框架中间件里。
5. 控制流
if err != nil { return ..., err }是常态,没有try/catch。defer:函数返回前执行(关文件、Cleanup()),后写的 defer 先执行。for是唯一循环;range遍历切片/map/channel。switch不用写break,默认不会落到下一分支(和 C 不同)。
6. 接口
- 接口是 隐式实现 :有方法就算实现,不用写
implements。 - 小接口更常见(
error就一个Error() string)。 - 接口变量底层是「类型 + 值」;值为
nil但带着类型时,== nil可能是false(踩坑点)。
7. 切片、map、append
- 切片是对底层数组的视图:
len/cap。 append可能换新数组,必须接住返回值。- map 零值是
nil,读可以、写之前要make。 - map 遍历顺序每次不一定相同。
8. 并发
go f()开 goroutine,和线程不是 1:1。- channel 用来通信;向已关闭的 channel 发送会 panic。
- 没有内置的「共享内存加锁就安全」保证,数据竞争要自己避免(
sync.Mutex或不要共享)。 init.go里那种go uc.createKnowledgeWithRetry就是语言级的 goroutine。
9. 官方习惯(不是语法强制,但大家当规则用)
- 对外方法第一个参数常常是
ctx context.Context(本仓库硬性要求)。 - 短接收者名:
func (s *AuditTaskService),不用this。 - 错误先处理,成功逻辑往下写,少套一层
else。 - 包名小写、不用下划线:
bootstrap、audit_task是文件名,包名仍是service/biz。 - 格式化用
gofmt/goimports,空格缩进、大括号风格都是固定的。
想系统过一遍,官方 A Tour of Go 比一次性背完整语言规范有效。