所有指针型AST字段链式访问前必须逐级判空,否则运行时panic;标识符统一为*ast.Ident,需先判空再取.Name;BasicLit需判Kind==token.STRING再Unquote;ImportSpec.Path需判空后strconv.Unquote去引号。

直接取 node.Name.Name、field.Type、is.Path.Value 这类链式字段前,必须先判空;漏掉中间任意一级 nil 检查,运行时就 panic。
FuncDecl.Name 是 *ast.Ident,不是 string
Go AST 把所有标识符(函数名、变量名、类型名)都统一建模为 *ast.Ident,它带位置和作用域信息,不是裸字符串。所以 fd.Name 是指针,fd.Name.Name 才是函数名字符串。
- 不判空直接写
fd.Name.Name:若遇到匿名函数(func() {}),fd.Name为 nil,解引用 panic - 误用
fmt.Sprintf("%v", fd.Name):输出的是内存地址,不是名字 - 所有
*ast.Ident字段(如Field.Names[0]、ImportSpec.Name)都要走.Name取值,且必须先!= nil
StructType.Fields.List 中的 *ast.Field 要分情况展开
*ast.Field 是多态结构:可能表示命名字段(Names 非空)、嵌入字段(Names 为空但 Type 是 *ast.Ident)、或多个同类型字段(Names 是切片)。硬遍历 Names 会漏掉嵌入字段。
- 先检查
field.Names != nil,再遍历field.Names取字段名 - 若
field.Names == nil且field.Type != nil,大概率是嵌入字段(如io.Reader) - 提取 tag 时,
field.Tag是*ast.BasicLit,值形如`json:"name"`,需用strings.Trim(field.Tag.Value, "`")去反引号
ImportSpec.Path.Value 带引号,不能直接当路径用
ImportSpec.Path 是 *ast.BasicLit,其 Value 是带双引号的字面量(如 ""fmt""),不是裸路径字符串。直接用会导致路径错误或 panic。
立即学习“go语言免费学习笔记(深入)”;
- 必须先判空:
if is.Path != nil,否则解引用 panic - 用
strconv.Unquote(is.Path.Value)安全去引号,它能正确处理转义(如""a\tb"") -
strings.Trim(is.Path.Value, `"`)不可靠,无法处理""foo\nbar""这类 -
is.Name是别名(如json "encoding/json"中的json),不影响路径提取,但需识别点导入或下划线导入时可忽略
BasicLit.Kind == token.STRING 才是字符串常量
字符串字面量("hello" 和 `world`)在 AST 中都归为 *ast.BasicLit,但只有 Kind == token.STRING 才是字符串——数字、布尔、nil 字面量也走这个节点类型。
- 别只看
node.Value是否含引号,要先做类型和 Kind 判断:lit, ok := node.(*ast.BasicLit); ok && lit.Kind == token.STRING - 用
strconv.Unquote(lit.Value)解析真实内容,它自动处理转义和 Unicode(如"u4f60") - 修改字符串必须替换父节点引用,不能改
lit.Value字段本身——它是只读的,改了也不生效
最易被忽略的是:所有指针型 AST 字段(*ast.Ident、*ast.BasicLit、*ast.ImportSpec 等)在链式访问前都得逐级判空,没有例外。AST 不保证非空,编译器不会帮你兜底。


















