如何使用Golang读取Go文件并解析其中struct属性?
实现方案
不要自己写正则匹配源码,Go标准库自带的AST解析工具链可以100%准确解析Go语法,不会被注释、换行、多字段同声明等特殊写法干扰,核心用到go/ast、go/parser、go/token三个标准包。
前置示例
假设待解析的car.go内容如下:
// car.go package model type Car struct { Brand string `json:"brand"` Price float64 `json:"price"` Year int `json:"year"` IsEV bool `json:"is_ev"` }
实现代码
核心逻辑分四步:
- 创建用于记录源码位置信息的文件集
- 解析目标Go文件生成AST语法树
- 遍历AST节点找到名为
Car的结构体声明 - 遍历结构体的字段列表,提取所有属性的名称、类型、标签信息
完整可运行代码:
package main import ( "fmt" "go/ast" "go/parser" "go/token" "os" ) // StructField 存储提取到的结构体属性信息 type StructField struct { FieldName string FieldType string Tag string } func main() { targetFile := "./car.go" fset := token.NewFileSet() // 解析源码文件,保留注释信息 f, err := parser.ParseFile(fset, targetFile, nil, parser.ParseComments) if err != nil { fmt.Printf("解析文件失败: %v\n", err) os.Exit(1) } var carFields []StructField // 遍历所有顶层声明 for _, decl := range f.Decls { genDecl, ok := decl.(*ast.GenDecl) if !ok { continue } // 遍历声明下的所有规格项 for _, spec := range genDecl.Specs { typeSpec, ok := spec.(*ast.TypeSpec) if !ok { continue } // 匹配名为Car的类型 if typeSpec.Name.Name != "Car" { continue } // 校验是否为结构体类型 structType, ok := typeSpec.Type.(*ast.StructType) if !ok { fmt.Println("Car标识符不是结构体类型") os.Exit(1) } // 遍历所有结构体字段 for _, field := range structType.Fields.List { // 处理同一声明下的多个同类型字段,比如 Brand,Alias string 这种写法 for _, name := range field.Names { sf := StructField{ FieldName: name.Name, FieldType: fmt.Sprint(field.Type), } // 提取字段标签,去掉两侧反引号 if field.Tag != nil { sf.Tag = field.Tag.Value[1 : len(field.Tag.Value)-1] } carFields = append(carFields, sf) } } } } // 输出提取结果 fmt.Printf("Car结构体共提取到%d个属性:\n", len(carFields)) for _, field := range carFields { fmt.Printf("- 字段名: %s | 类型: %s | 标签: %s\n", field.FieldName, field.FieldType, field.Tag) } }
运行结果
执行上述代码会输出:
Car结构体共提取到4个属性: - 字段名: Brand | 类型: string | 标签: json:"brand" - 字段名: Price | 类型: float64 | 标签: json:"price" - 字段名: Year | 类型: int | 标签: json:"year" - 字段名: IsEV | 类型: bool | 标签: json:"is_ev"
注意事项
- 禁止用正则解析Go源码:Go语法存在大量特殊写法(多行字段、字段间穿插注释、同类型多字段合并声明、嵌套结构体等),正则匹配的漏判、错判率极高,标准库AST解析完全遵循Go语法规范,稳定性有保障。
- 如果目标结构体定义在函数内部而非顶层,需要额外遍历函数体的AST节点做匹配,绝大多数业务场景下结构体都是顶层声明,上述代码可以直接覆盖。
- 如果需要解析跨包引用的字段类型(比如字段是其他包导出的结构体类型),可以搭配
go/packages包做全项目类型加载,简单提取字段名、基础类型、标签的场景下上述代码已经足够。
内容的提问来源于stack exchange,提问作者Luiz Felipe Limão
相关产品推荐
相关产品推荐

