os.MkdirAll是Go中创建多级嵌套目录的唯一推荐方案,它自动递归创建所有缺失父目录、路径已存在时静默成功,权限0755应用于所有新建目录,且跨平台兼容路径分隔符/。

用 os.MkdirAll 一次性创建多级嵌套目录
Go 里处理嵌套目录,os.MkdirAll 是唯一推荐方案,别自己拆路径、循环调 os.Mkdir。它自动补全所有缺失父目录,路径已存在时静默成功,完全符合“创建即幂等”的工程直觉。
常见错误是手动拼接路径后误用 \ 分隔符(尤其在 Windows 开发环境),导致跨平台失败。Go 运行时能自动转换 /,但 \ 在字符串中容易引发转义问题或路径不匹配。
-
os.MkdirAll("a/b/c", 0755)—— 正确:自动创建a、a/b、a/b/c - 权限参数
0755应用于**所有新建目录**,已存在目录的权限不受影响 - 错误返回仅表示“创建失败”,不是“已存在”;
err == nil即代表目标路径已是有效目录(无论是否新建)
用 embed.FS 安全读取嵌套资源文件
embed.FS 不会自动递归包含子目录,//go:embed assets/ 只嵌入一级文件,assets/css/main.css 必然报 no such file or directory。
必须显式写 //go:embed assets/**(双星号),且所有运行时路径都需带完整前缀、用 / 分隔。硬编码路径末尾加斜杠(如 "assets/css/")会导致 fs.ReadFile panic,因为它只接受文件路径,不接受目录路径。
立即学习“go语言免费学习笔记(深入)”;
- 检查是否为文件再读取:
info, _ := fs.Stat(path); if !info.IsDir() { fs.ReadFile(path) } - 遍历目录必须逐层
fs.ReadDir("assets") → fs.ReadDir("assets/img"),不能指望一次调用返回全树 - 绝对不要用
filepath.Join拼接路径传给fs.ReadFile,它在 Windows 上生成\,embed.FS不识别
用 reflect 递归遍历嵌套结构体时防 panic
反射访问嵌套结构体最常因未解引用指针、访问非导出字段或无限循环而 panic。核心原则是:先 IsValid(),再判 Kind(),对 reflect.Ptr 和 reflect.Interface 必须 .Elem() 后才可继续;对 struct 字段只能遍历导出字段(首字母大写)。
循环引用(如 type A struct { Next *A })不加防护会栈溢出。深度限制比地址缓存更简单可靠——多数业务场景嵌套超 5 层就该报警,而非强行展开。
- 进入递归前加深度判断:
if depth > 5 { return } - 对
reflect.Map、reflect.Slice、reflect.Struct才继续递归,其他类型(int/string等)直接取.Interface() - 避免对
reflect.Value调用.UnsafeAddr()前不检查.CanAddr(),否则在 map value 或函数返回值上会 panic
用 json.RawMessage 处理动态嵌套 JSON
直接 json.Unmarshal 到结构体遇到字段类型不一致(比如同名 children 有时是 array、有时是 null、有时是 object)必然 panic:json: cannot unmarshal object into Go struct field。
根本解法不是用 interface{} + 套娃类型断言,而是把不确定的部分声明为 json.RawMessage,延迟解析。它只是字节切片包装,零开销、无类型约束,真正需要时再二次 json.Unmarshal。
- 结构体字段定义为
Children json.RawMessage `json:"children,omitempty"`,不是[]Node也不是interface{} - 递归解析函数接收
json.RawMessage,先尝试json.Unmarshal成map[string]interface{}判断"type"字段,再决定分支逻辑 - 同一段
json.RawMessage可多次Unmarshal,但它是只读切片,不能像io.Reader那样反复读取


















