Skip to content

Go代码生成技术 - Golang元编程和自动化代码生成

代码生成是Go语言中重要的元编程技术,能够自动生成重复性代码,提高开发效率,减少错误。掌握代码生成技术对于构建高质量的Go工具和框架至关重要。

📋 重点面试题

面试题 1:Go代码生成的实现原理和应用实践

难度级别:⭐⭐⭐⭐⭐
考察范围:元编程/工具开发
技术标签code generation metaprogramming ast template

详细解答

1. 代码生成核心技术

go
package main

import (
    "bytes"
    "fmt"
    "go/ast"
    "go/format"
    "go/parser"
    "go/token"
    "os"
    "path/filepath"
    "strings"
    "text/template"
)

func demonstrateCodeGeneration() {
    fmt.Println("=== Go代码生成技术 ===")
    
    /*
    代码生成技术体系:
    
    1. 模板驱动生成:
       - text/template包
       - html/template包
       - 自定义模板引擎
       - 模板函数扩展
    
    2. AST分析生成:
       - go/parser解析
       - go/ast遍历
       - go/types类型检查
       - 代码转换和生成
    
    3. 代码生成工具:
       - go generate命令
       - stringer工具
       - protobuf编译器
       - mockgen等Mock工具
    
    4. 应用场景:
       - 接口实现生成
       - 序列化代码生成
       - Mock对象生成
       - 数据库模型生成
    */
    
    demonstrateTemplateGeneration()
    demonstrateASTAnalysis()
    demonstrateInterfaceGeneration()
    demonstrateGoGenerate()
}

func demonstrateTemplateGeneration() {
    fmt.Println("\n--- 模板驱动代码生成 ---")
    
    /*
    模板生成要点:
    
    1. 模板定义和解析
    2. 数据模型设计
    3. 自定义函数注册
    4. 代码格式化
    */
    
    // 代码生成器
    type CodeGenerator struct {
        templates map[string]*template.Template
        funcMap   template.FuncMap
    }
    
    func NewCodeGenerator() *CodeGenerator {
        cg := &CodeGenerator{
            templates: make(map[string]*template.Template),
            funcMap: template.FuncMap{
                "title":      strings.Title,
                "lower":      strings.ToLower,
                "upper":      strings.ToUpper,
                "camelCase":  toCamelCase,
                "snakeCase":  toSnakeCase,
                "pluralize":  pluralize,
            },
        }
        return cg
    }
    
    func toCamelCase(s string) string {
        words := strings.Split(s, "_")
        for i := range words {
            if i > 0 && len(words[i]) > 0 {
                words[i] = strings.ToUpper(words[i][:1]) + words[i][1:]
            }
        }
        return strings.Join(words, "")
    }
    
    func toSnakeCase(s string) string {
        var result strings.Builder
        for i, r := range s {
            if i > 0 && r >= 'A' && r <= 'Z' {
                result.WriteRune('_')
            }
            result.WriteRune(r)
        }
        return strings.ToLower(result.String())
    }
    
    func pluralize(s string) string {
        if strings.HasSuffix(s, "y") {
            return s[:len(s)-1] + "ies"
        }
        if strings.HasSuffix(s, "s") {
            return s + "es"
        }
        return s + "s"
    }
    
    func (cg *CodeGenerator) AddTemplate(name, tmplStr string) error {
        tmpl, err := template.New(name).Funcs(cg.funcMap).Parse(tmplStr)
        if err != nil {
            return fmt.Errorf("模板解析失败: %v", err)
        }
        cg.templates[name] = tmpl
        return nil
    }
    
    func (cg *CodeGenerator) Generate(templateName string, data interface{}) (string, error) {
        tmpl, exists := cg.templates[templateName]
        if !exists {
            return "", fmt.Errorf("模板 %s 不存在", templateName)
        }
        
        var buf bytes.Buffer
        if err := tmpl.Execute(&buf, data); err != nil {
            return "", fmt.Errorf("模板执行失败: %v", err)
        }
        
        // 格式化生成的代码
        formatted, err := format.Source(buf.Bytes())
        if err != nil {
            // 如果格式化失败,返回未格式化的代码
            return buf.String(), nil
        }
        
        return string(formatted), nil
    }
    
    // 数据模型定义
    type StructDef struct {
        PackageName string
        StructName  string
        Fields      []FieldDef
        Methods     []MethodDef
    }
    
    type FieldDef struct {
        Name string
        Type string
        Tags string
    }
    
    type MethodDef struct {
        Name       string
        ReceiverType string
        Params     []ParamDef
        Returns    []string
        Body       string
    }
    
    type ParamDef struct {
        Name string
        Type string
    }
    
    // CRUD代码生成模板
    const crudTemplate = `package {{.PackageName}}

import (
    "context"
    "database/sql"
    "fmt"
)

// {{.StructName}} 数据模型
type {{.StructName}} struct {
{{range .Fields}}    {{.Name}} {{.Type}} {{.Tags}}
{{end}}}

// {{.StructName}}Repository 数据访问层
type {{.StructName}}Repository struct {
    db *sql.DB
}

// New{{.StructName}}Repository 创建仓储实例
func New{{.StructName}}Repository(db *sql.DB) *{{.StructName}}Repository {
    return &{{.StructName}}Repository{db: db}
}

// Create 创建记录
func (r *{{.StructName}}Repository) Create(ctx context.Context, entity *{{.StructName}}) error {
    query := "INSERT INTO {{snakeCase .StructName | pluralize}} ({{range $i, $f := .Fields}}{{if $i}}, {{end}}{{snakeCase $f.Name}}{{end}}) VALUES ({{range $i, $f := .Fields}}{{if $i}}, {{end}}${{add $i 1}}{{end}})"
    
    _, err := r.db.ExecContext(ctx, query{{range .Fields}}, entity.{{.Name}}{{end}})
    return err
}

// FindByID 根据ID查找
func (r *{{.StructName}}Repository) FindByID(ctx context.Context, id int64) (*{{.StructName}}, error) {
    query := "SELECT {{range $i, $f := .Fields}}{{if $i}}, {{end}}{{snakeCase $f.Name}}{{end}} FROM {{snakeCase .StructName | pluralize}} WHERE id = $1"
    
    entity := &{{.StructName}}{}
    err := r.db.QueryRowContext(ctx, query, id).Scan({{range $i, $f := .Fields}}{{if $i}}, {{end}}&entity.{{$f.Name}}{{end}})
    
    if err == sql.ErrNoRows {
        return nil, fmt.Errorf("记录不存在")
    }
    return entity, err
}

// Update 更新记录
func (r *{{.StructName}}Repository) Update(ctx context.Context, entity *{{.StructName}}) error {
    query := "UPDATE {{snakeCase .StructName | pluralize}} SET {{range $i, $f := .Fields}}{{if ne $f.Name "ID"}}{{if $i}}, {{end}}{{snakeCase $f.Name}} = ${{$i}}{{end}}{{end}} WHERE id = ${{len .Fields}}"
    
    _, err := r.db.ExecContext(ctx, query{{range .Fields}}{{if ne .Name "ID"}}, entity.{{.Name}}{{end}}{{end}}, entity.ID)
    return err
}

// Delete 删除记录
func (r *{{.StructName}}Repository) Delete(ctx context.Context, id int64) error {
    query := "DELETE FROM {{snakeCase .StructName | pluralize}} WHERE id = $1"
    
    _, err := r.db.ExecContext(ctx, query, id)
    return err
}

// List 列出所有记录
func (r *{{.StructName}}Repository) List(ctx context.Context, limit, offset int) ([]*{{.StructName}}, error) {
    query := "SELECT {{range $i, $f := .Fields}}{{if $i}}, {{end}}{{snakeCase $f.Name}}{{end}} FROM {{snakeCase .StructName | pluralize}} LIMIT $1 OFFSET $2"
    
    rows, err := r.db.QueryContext(ctx, query, limit, offset)
    if err != nil {
        return nil, err
    }
    defer rows.Close()
    
    var entities []*{{.StructName}}
    for rows.Next() {
        entity := &{{.StructName}}{}
        if err := rows.Scan({{range $i, $f := .Fields}}{{if $i}}, {{end}}&entity.{{$f.Name}}{{end}}); err != nil {
            return nil, err
        }
        entities = append(entities, entity)
    }
    
    return entities, rows.Err()
}
`
    
    // 演示模板生成
    fmt.Printf("模板驱动代码生成演示:\n")
    
    generator := NewCodeGenerator()
    
    // 添加模板
    if err := generator.AddTemplate("crud", crudTemplate); err != nil {
        fmt.Printf("  ❌ 添加模板失败: %v\n", err)
        return
    }
    
    // 定义数据模型
    userModel := StructDef{
        PackageName: "user",
        StructName:  "User",
        Fields: []FieldDef{
            {Name: "ID", Type: "int64", Tags: "`json:\"id\" db:\"id\"`"},
            {Name: "Name", Type: "string", Tags: "`json:\"name\" db:\"name\"`"},
            {Name: "Email", Type: "string", Tags: "`json:\"email\" db:\"email\"`"},
            {Name: "Age", Type: "int", Tags: "`json:\"age\" db:\"age\"`"},
            {Name: "CreatedAt", Type: "time.Time", Tags: "`json:\"created_at\" db:\"created_at\"`"},
        },
    }
    
    // 生成代码
    code, err := generator.Generate("crud", userModel)
    if err != nil {
        fmt.Printf("  ❌ 代码生成失败: %v\n", err)
        return
    }
    
    fmt.Printf("  ✅ 成功生成User模型CRUD代码\n")
    fmt.Printf("  📝 生成的代码长度: %d bytes\n", len(code))
    fmt.Printf("  📄 代码预览(前500字符):\n")
    preview := code
    if len(preview) > 500 {
        preview = preview[:500] + "..."
    }
    fmt.Println(preview)
}

func demonstrateASTAnalysis() {
    fmt.Println("\n--- AST分析和代码生成 ---")
    
    /*
    AST分析要点:
    
    1. 源代码解析
    2. AST节点遍历
    3. 类型信息提取
    4. 代码转换生成
    */
    
    // AST分析器
    type ASTAnalyzer struct {
        fset *token.FileSet
    }
    
    func NewASTAnalyzer() *ASTAnalyzer {
        return &ASTAnalyzer{
            fset: token.NewFileSet(),
        }
    }
    
    func (aa *ASTAnalyzer) ParseFile(filename string) (*ast.File, error) {
        return parser.ParseFile(aa.fset, filename, nil, parser.ParseComments)
    }
    
    func (aa *ASTAnalyzer) ParseSource(source string) (*ast.File, error) {
        return parser.ParseFile(aa.fset, "source.go", source, parser.ParseComments)
    }
    
    func (aa *ASTAnalyzer) ExtractStructs(file *ast.File) []StructInfo {
        var structs []StructInfo
        
        ast.Inspect(file, func(n ast.Node) bool {
            // 查找类型声明
            typeSpec, ok := n.(*ast.TypeSpec)
            if !ok {
                return true
            }
            
            // 查找结构体类型
            structType, ok := typeSpec.Type.(*ast.StructType)
            if !ok {
                return true
            }
            
            info := StructInfo{
                Name:   typeSpec.Name.Name,
                Fields: make([]StructFieldInfo, 0),
            }
            
            // 遍历字段
            for _, field := range structType.Fields.List {
                for _, name := range field.Names {
                    fieldInfo := StructFieldInfo{
                        Name: name.Name,
                        Type: aa.exprToString(field.Type),
                    }
                    
                    if field.Tag != nil {
                        fieldInfo.Tag = field.Tag.Value
                    }
                    
                    info.Fields = append(info.Fields, fieldInfo)
                }
            }
            
            structs = append(structs, info)
            return true
        })
        
        return structs
    }
    
    func (aa *ASTAnalyzer) exprToString(expr ast.Expr) string {
        switch t := expr.(type) {
        case *ast.Ident:
            return t.Name
        case *ast.StarExpr:
            return "*" + aa.exprToString(t.X)
        case *ast.ArrayType:
            return "[]" + aa.exprToString(t.Elt)
        case *ast.MapType:
            return "map[" + aa.exprToString(t.Key) + "]" + aa.exprToString(t.Value)
        case *ast.SelectorExpr:
            return aa.exprToString(t.X) + "." + t.Sel.Name
        default:
            return "unknown"
        }
    }
    
    type StructInfo struct {
        Name   string
        Fields []StructFieldInfo
    }
    
    type StructFieldInfo struct {
        Name string
        Type string
        Tag  string
    }
    
    // Getter/Setter生成器
    func (aa *ASTAnalyzer) GenerateGettersSetters(info StructInfo) string {
        var buf bytes.Buffer
        
        for _, field := range info.Fields {
            // 生成Getter
            fmt.Fprintf(&buf, "// Get%s 获取%s字段\n", field.Name, field.Name)
            fmt.Fprintf(&buf, "func (o *%s) Get%s() %s {\n", info.Name, field.Name, field.Type)
            fmt.Fprintf(&buf, "    return o.%s\n", field.Name)
            fmt.Fprintf(&buf, "}\n\n")
            
            // 生成Setter
            fmt.Fprintf(&buf, "// Set%s 设置%s字段\n", field.Name, field.Name)
            fmt.Fprintf(&buf, "func (o *%s) Set%s(value %s) {\n", info.Name, field.Name, field.Type)
            fmt.Fprintf(&buf, "    o.%s = value\n", field.Name)
            fmt.Fprintf(&buf, "}\n\n")
        }
        
        // 格式化代码
        formatted, err := format.Source(buf.Bytes())
        if err != nil {
            return buf.String()
        }
        
        return string(formatted)
    }
    
    // 演示AST分析
    fmt.Printf("AST分析和代码生成演示:\n")
    
    analyzer := NewASTAnalyzer()
    
    // 示例源代码
    source := `package example

type Person struct {
    Name  string
    Age   int
    Email string
}
`
    
    // 解析源代码
    file, err := analyzer.ParseSource(source)
    if err != nil {
        fmt.Printf("  ❌ 解析失败: %v\n", err)
        return
    }
    
    // 提取结构体信息
    structs := analyzer.ExtractStructs(file)
    
    fmt.Printf("  🔍 发现 %d 个结构体:\n", len(structs))
    
    for _, structInfo := range structs {
        fmt.Printf("    结构体: %s\n", structInfo.Name)
        fmt.Printf("      字段数: %d\n", len(structInfo.Fields))
        
        for _, field := range structInfo.Fields {
            fmt.Printf("        - %s: %s\n", field.Name, field.Type)
        }
        
        // 生成Getter/Setter
        code := analyzer.GenerateGettersSetters(structInfo)
        
        fmt.Printf("\n  📝 生成的Getter/Setter代码:\n")
        preview := code
        if len(preview) > 500 {
            preview = preview[:500] + "..."
        }
        fmt.Println(preview)
    }
}

func demonstrateInterfaceGeneration() {
    fmt.Println("\n--- 接口实现代码生成 ---")
    
    /*
    接口生成要点:
    
    1. 接口定义解析
    2. 方法签名提取
    3. 实现代码生成
    4. Mock对象生成
    */
    
    // 接口生成器
    type InterfaceGenerator struct {
        analyzer *ASTAnalyzer
    }
    
    func NewInterfaceGenerator() *InterfaceGenerator {
        return &InterfaceGenerator{
            analyzer: NewASTAnalyzer(),
        }
    }
    
    func (ig *InterfaceGenerator) ExtractInterface(source string) (*InterfaceInfo, error) {
        file, err := ig.analyzer.ParseSource(source)
        if err != nil {
            return nil, err
        }
        
        var interfaceInfo *InterfaceInfo
        
        ast.Inspect(file, func(n ast.Node) bool {
            typeSpec, ok := n.(*ast.TypeSpec)
            if !ok {
                return true
            }
            
            interfaceType, ok := typeSpec.Type.(*ast.InterfaceType)
            if !ok {
                return true
            }
            
            interfaceInfo = &InterfaceInfo{
                Name:    typeSpec.Name.Name,
                Methods: make([]InterfaceMethodInfo, 0),
            }
            
            for _, method := range interfaceType.Methods.List {
                if len(method.Names) == 0 {
                    continue
                }
                
                funcType, ok := method.Type.(*ast.FuncType)
                if !ok {
                    continue
                }
                
                methodInfo := InterfaceMethodInfo{
                    Name:    method.Names[0].Name,
                    Params:  ig.extractParams(funcType.Params),
                    Results: ig.extractResults(funcType.Results),
                }
                
                interfaceInfo.Methods = append(interfaceInfo.Methods, methodInfo)
            }
            
            return false
        })
        
        return interfaceInfo, nil
    }
    
    func (ig *InterfaceGenerator) extractParams(fieldList *ast.FieldList) []ParamInfo {
        if fieldList == nil {
            return nil
        }
        
        var params []ParamInfo
        for _, field := range fieldList.List {
            typeName := ig.analyzer.exprToString(field.Type)
            
            if len(field.Names) == 0 {
                params = append(params, ParamInfo{Type: typeName})
            } else {
                for _, name := range field.Names {
                    params = append(params, ParamInfo{
                        Name: name.Name,
                        Type: typeName,
                    })
                }
            }
        }
        return params
    }
    
    func (ig *InterfaceGenerator) extractResults(fieldList *ast.FieldList) []string {
        if fieldList == nil {
            return nil
        }
        
        var results []string
        for _, field := range fieldList.List {
            typeName := ig.analyzer.exprToString(field.Type)
            count := len(field.Names)
            if count == 0 {
                count = 1
            }
            for i := 0; i < count; i++ {
                results = append(results, typeName)
            }
        }
        return results
    }
    
    type InterfaceInfo struct {
        Name    string
        Methods []InterfaceMethodInfo
    }
    
    type InterfaceMethodInfo struct {
        Name    string
        Params  []ParamInfo
        Results []string
    }
    
    type ParamInfo struct {
        Name string
        Type string
    }
    
    func (ig *InterfaceGenerator) GenerateMock(info *InterfaceInfo, mockName string) string {
        var buf bytes.Buffer
        
        // 生成Mock结构体
        fmt.Fprintf(&buf, "// %s%s 接口的Mock实现\n", mockName, info.Name)
        fmt.Fprintf(&buf, "type %s struct {\n", mockName)
        
        for _, method := range info.Methods {
            fmt.Fprintf(&buf, "    %sFunc func(", method.Name)
            for i, param := range method.Params {
                if i > 0 {
                    buf.WriteString(", ")
                }
                if param.Name != "" {
                    fmt.Fprintf(&buf, "%s ", param.Name)
                }
                buf.WriteString(param.Type)
            }
            buf.WriteString(")")
            
            if len(method.Results) > 0 {
                buf.WriteString(" (")
                for i, result := range method.Results {
                    if i > 0 {
                        buf.WriteString(", ")
                    }
                    buf.WriteString(result)
                }
                buf.WriteString(")")
            }
            buf.WriteString("\n")
        }
        
        fmt.Fprintf(&buf, "}\n\n")
        
        // 生成方法实现
        for _, method := range info.Methods {
            fmt.Fprintf(&buf, "func (m *%s) %s(", mockName, method.Name)
            
            for i, param := range method.Params {
                if i > 0 {
                    buf.WriteString(", ")
                }
                if param.Name != "" {
                    fmt.Fprintf(&buf, "%s ", param.Name)
                } else {
                    fmt.Fprintf(&buf, "arg%d ", i)
                }
                buf.WriteString(param.Type)
            }
            
            buf.WriteString(")")
            
            if len(method.Results) > 0 {
                buf.WriteString(" (")
                for i, result := range method.Results {
                    if i > 0 {
                        buf.WriteString(", ")
                    }
                    buf.WriteString(result)
                }
                buf.WriteString(")")
            }
            
            buf.WriteString(" {\n")
            
            // 调用Mock函数
            fmt.Fprintf(&buf, "    if m.%sFunc != nil {\n", method.Name)
            if len(method.Results) > 0 {
                buf.WriteString("        return ")
            } else {
                buf.WriteString("        ")
            }
            
            fmt.Fprintf(&buf, "m.%sFunc(", method.Name)
            for i, param := range method.Params {
                if i > 0 {
                    buf.WriteString(", ")
                }
                if param.Name != "" {
                    buf.WriteString(param.Name)
                } else {
                    fmt.Fprintf(&buf, "arg%d", i)
                }
            }
            buf.WriteString(")\n")
            buf.WriteString("    }\n")
            
            // 默认返回零值
            if len(method.Results) > 0 {
                buf.WriteString("    return")
                for i, result := range method.Results {
                    if i > 0 {
                        buf.WriteString(",")
                    }
                    buf.WriteString(" ")
                    buf.WriteString(ig.getZeroValue(result))
                }
                buf.WriteString("\n")
            }
            
            buf.WriteString("}\n\n")
        }
        
        formatted, err := format.Source(buf.Bytes())
        if err != nil {
            return buf.String()
        }
        
        return string(formatted)
    }
    
    func (ig *InterfaceGenerator) getZeroValue(typeName string) string {
        switch typeName {
        case "string":
            return `""`
        case "int", "int8", "int16", "int32", "int64",
            "uint", "uint8", "uint16", "uint32", "uint64",
            "byte", "rune", "float32", "float64":
            return "0"
        case "bool":
            return "false"
        case "error":
            return "nil"
        default:
            return "nil"
        }
    }
    
    // 演示接口实现生成
    fmt.Printf("接口实现代码生成演示:\n")
    
    generator := NewInterfaceGenerator()
    
    // 示例接口
    interfaceSource := `package example

type UserService interface {
    GetUser(id int64) (*User, error)
    CreateUser(name, email string) (*User, error)
    UpdateUser(id int64, name, email string) error
    DeleteUser(id int64) error
}
`
    
    // 提取接口信息
    interfaceInfo, err := generator.ExtractInterface(interfaceSource)
    if err != nil {
        fmt.Printf("  ❌ 提取接口失败: %v\n", err)
        return
    }
    
    fmt.Printf("  🔍 接口分析:\n")
    fmt.Printf("    接口名: %s\n", interfaceInfo.Name)
    fmt.Printf("    方法数: %d\n", len(interfaceInfo.Methods))
    
    for _, method := range interfaceInfo.Methods {
        fmt.Printf("      - %s (参数: %d, 返回值: %d)\n", 
            method.Name, len(method.Params), len(method.Results))
    }
    
    // 生成Mock实现
    mockCode := generator.GenerateMock(interfaceInfo, "Mock"+interfaceInfo.Name)
    
    fmt.Printf("\n  📝 生成的Mock代码:\n")
    preview := mockCode
    if len(preview) > 800 {
        preview = preview[:800] + "..."
    }
    fmt.Println(preview)
}

func demonstrateGoGenerate() {
    fmt.Println("\n--- go generate 工具集成 ---")
    
    /*
    go generate要点:
    
    1. 生成指令编写
    2. 工具集成
    3. 构建流程
    4. 最佳实践
    */
    
    fmt.Printf("go generate 工具使用示例:\n")
    
    // 创建示例文件
    exampleFile := `package user

//go:generate go run github.com/golang/mock/mockgen -destination=mock_user_service.go -package=user UserService

// User 用户模型
type User struct {
    ID    int64
    Name  string
    Email string
}

// UserService 用户服务接口
//go:generate mockgen -source=user.go -destination=mock_user_service.go -package=user
type UserService interface {
    GetUser(id int64) (*User, error)
    CreateUser(name, email string) (*User, error)
}

//go:generate stringer -type=Status
type Status int

const (
    StatusActive Status = iota
    StatusInactive
    StatusDeleted
)
`
    
    fmt.Printf("  📝 示例代码:\n")
    lines := strings.Split(exampleFile, "\n")
    for i, line := range lines {
        if i > 20 {
            fmt.Printf("    ... (省略 %d 行)\n", len(lines)-i)
            break
        }
        fmt.Printf("    %s\n", line)
    }
    
    fmt.Printf("\n  🔧 go generate 指令说明:\n")
    fmt.Printf("    1. mockgen: 生成接口的Mock实现\n")
    fmt.Printf("       //go:generate mockgen -source=file.go -destination=mock.go\n")
    fmt.Printf("    2. stringer: 为枚举类型生成String()方法\n")
    fmt.Printf("       //go:generate stringer -type=TypeName\n")
    fmt.Printf("    3. protoc: 生成protobuf代码\n")
    fmt.Printf("       //go:generate protoc --go_out=. proto/*.proto\n")
    
    fmt.Printf("\n  📋 使用步骤:\n")
    fmt.Printf("    1. 在代码中添加 //go:generate 注释\n")
    fmt.Printf("    2. 运行 go generate ./...\n")
    fmt.Printf("    3. 生成的代码会自动创建\n")
    fmt.Printf("    4. 将生成的代码纳入版本控制\n")
    
    fmt.Printf("\n  ✅ 最佳实践:\n")
    fmt.Printf("    1. 将生成的代码提交到版本控制系统\n")
    fmt.Printf("    2. 在CI/CD中验证代码是最新的\n")
    fmt.Printf("    3. 使用明确的生成工具版本\n")
    fmt.Printf("    4. 为生成的文件添加构建标签\n")
    fmt.Printf("    5. 文档说明生成过程和依赖\n")
}

func main() {
    demonstrateCodeGeneration()
}

🎯 核心知识点总结

模板生成要点

  1. 模板定义: 使用text/template定义代码模板
  2. 自定义函数: 注册模板函数扩展功能
  3. 数据模型: 设计清晰的数据结构驱动生成
  4. 代码格式化: 使用go/format格式化生成的代码

AST分析要点

  1. 源码解析: 使用go/parser解析Go源代码
  2. 节点遍历: 通过ast.Inspect遍历AST节点
  3. 信息提取: 提取类型、字段、方法等信息
  4. 代码生成: 基于AST信息生成新代码

接口生成要点

  1. 接口解析: 提取接口定义和方法签名
  2. Mock生成: 自动生成测试用Mock实现
  3. 参数处理: 正确处理方法参数和返回值
  4. 零值生成: 为不同类型生成合适的零值

go generate要点

  1. 指令编写: 正确编写go:generate注释
  2. 工具集成: 集成mockgen、stringer等工具
  3. 版本控制: 管理生成代码的版本
  4. CI集成: 在持续集成中验证代码生成

🔍 面试准备建议

  1. 理解原理: 深入理解AST和代码生成原理
  2. 工具熟练: 掌握常用代码生成工具的使用
  3. 模板设计: 学会设计灵活可扩展的代码模板
  4. 实践经验: 积累编写代码生成器的实际经验
  5. 最佳实践: 了解代码生成的最佳实践和注意事项

正在精进