多数场景下应选 Trie 而非 suffixarray:Trie 天然支持前缀匹配与 DFS 收集补全项,结构清晰、可控性强;suffixarray 多词补全易因分隔符冲突、跨边界等问题出错,仅适用于超大只读词库且内存极度敏感的特例。

补全逻辑该用 Trie 还是 suffixarray?
多数场景下直接上 Trie 更稳妥。虽然 index/suffixarray 在单字符串长文本中匹配快,但“搜索建议”本质是前缀匹配一堆离散词(比如用户输入 “he” 想看到 “hello”“hero”“help”),Trie 天然支持 StartsWith + DFS 收集,结构清晰、可控性强。
suffixarray 要支持多词补全得靠拼接 + 分隔符(如 \x00),但分隔符一旦出现在原始词里就崩;正则匹配还要防跨边界;且返回结果需二次切分还原,容易出错。除非你已有超大只读词库且对内存极度敏感,否则没必要绕路。
- 中文/emoji 必须用
map[rune]Node,不是map[byte]Node—— 否则 “你好” 会被拆成 6 个字节,Search("你好")永远失败 - 自动补全函数里别直接拼字符串,用
strings.Builder或预分配 slice,避免 GC 频繁触发 - 必须限制补全数量(如最多 10 条),DFS 一达到就
return,别等遍历完——树深一点就卡住
为什么 Search 和 StartsWith 行为不同?
Search("he") 返回 false 是正常的,它只认完整词;而 StartsWith("he") 返回 true 才是你做补全的起点。两者语义不能混用。
-
Search要求路径存在 且 末节点isWord == true(即 “he” 本身得是词) -
StartsWith只检查路径存在(即有词以 “he” 开头),之后才进 DFS 收集所有isWord == true的叶子 - 常见错误:把
StartsWith当成 “是否存在候选”,然后自己再遍历整棵树——其实StartsWith就是快速守门员,先筛掉根本没戏的前缀
CLI 工具补全和编辑器补全完全不是一回事
别指望写个 Trie 就能让终端 mytool deploy <tab></tab> 出建议。CLI 补全是 shell 层的事,Go 程序只是被调用的一次性数据提供者。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
- 用
cobra的话,得生成 bash/zsh 补全脚本,并确保:- bash 脚本写入
/usr/local/etc/bash_completion.d/或被source进 shell - zsh 脚本名必须是
_mytool(开头下划线),放在fpath目录,末尾加compdef _mytool mytool - 动态补全函数里,
toComplete是用户已输部分(如 “pro”),不是完整参数值,要用strings.HasPrefix匹配,别用==
- bash 脚本写入
- 补全函数里禁止 HTTP 请求、文件扫描等耗时操作——shell 会等,用户会以为卡死
- 返回的
[]string切片里不能有空字符串或含空格项,否则整个补全中断
gopls 不工作?先看这三件事
VS Code / GoLand 补全失效,90% 和 gopls 本身无关,而是环境没对齐。
- 项目根目录必须有
go.mod(哪怕只是go mod init dummy),否则gopls降级为无类型模式,连 struct 字段都不提示 -
gopls必须在$PATH里:which gopls要有输出;装完记得go install golang.org/x/tools/gopls@latest再确认版本 - 别打开子目录(比如只开
cmd/mytool),要打开包含go.mod的最外层目录——gopls不会向上找go.mod - 国内用户注意
GOPROXY:如果设了私有代理但不可达,gopls初始化会静默超时,补全变灰
真正难搞的是补全建议顺序和字段可见性——这些藏在编辑器设置深处,比如 VS Code 的 go.gopls.completeUnimported 默认关着,不手动开就不会提示未导入包里的符号。

















