2022-11-13:以下go语言代码中,如何获取结构体列表以及结构体内的指针方法列表?

2022-11-13:以下go语言代码中,如何获取结构体列表以及结构体内的指针方法列表?以下代码应该返回{“S1”:[“M1”,”M2”],”S2”:[],”S3”:[“M1”,”M3”]},顺序不限。S1的M3方法不是指针方法,S3的M2方法也不是指针方法,所以不能输出。

package main
type S1 struct{}
func (this *S1) M1() {}
func (this *S1) M2() {}
func (this S1) M3() {}
type S2 struct{}
type S3 struct{}
func (this *S3) M1() {}
func (this S3) M2() {}
func (this *S3) M3() {}

答案2022-11-13:

这道题有人说用反射,实际上反射是无法解决这个问题的,原因是无法直接使用结构体。
要解析rust的代码,go/ast、go/parser、go/token,要用到这三个包。
使用场景是写框架。

代码用go语言编写。代码如下:

package main

import (
    "encoding/json"
    "fmt"
    "go/ast"
    "go/parser"
    "go/token"
)

const content = `package main
type S1 struct{}
func (this *S1) M1() {}
func (this *S1) M2() {}
func (this S1) M3() {}
type S2 struct{}
type S3 struct{}
func (this *S3) M1() {}
func (this S3) M2() {}
func (this *S3) M3() {}`

func main() {
    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, "", content, parser.ParseComments)
    if err != nil {
        fmt.Println(err)
        return
    }

    structInfoList := make([]*StructInfo, 0)
    structInfoMap := make(map[string]*StructInfo)

    // 找结构体
    for i := 0; i < len(f.Decls); i++ {
        decl, ok := f.Decls[i].(*ast.GenDecl)
        if !ok {
            continue
        }
        if decl.Tok != token.TYPE {
            continue
        }
        if len(decl.Specs) != 1 {
            continue
        }
        spec, ok2 := decl.Specs[0].(*ast.TypeSpec)
        if !ok2 {
            continue
        }
        structType, ok3 := spec.Type.(*ast.StructType)
        if !ok3 {
            fmt.Println("失败", structType)
            continue
        }
        structInfo := NewStructInfo(spec.Name.Name)
        structInfoList = append(structInfoList, structInfo)
        structInfoMap[spec.Name.Name] = structInfo
    }

    // 找方法
    for i := 0; i < len(f.Decls); i++ {
        decl, ok := f.Decls[i].(*ast.FuncDecl)
        if !ok {
            continue
        }
        if decl.Recv == nil || len(decl.Recv.List) != 1 {
            continue
        }
        structName := ""
        switch decl.Recv.List[0].Type.(type) {
        case *ast.StarExpr: //指针方法
            structName = decl.Recv.List[0].Type.(*ast.StarExpr).X.(*ast.Ident).Name
        case *ast.Ident: //普通方法
            //structName = decl.Recv.List[0].Type.(*ast.Ident).Name
        }
        if structInfo, ok := structInfoMap[structName]; ok {
            structInfo.MethodNameList = append(structInfo.MethodNameList, decl.Name.Name)
        }
    }

    // 输出
    data, _ := json.MarshalIndent(structInfoList, "", "  ")
    fmt.Println(string(data))
}

type StructInfo struct {
    StructName     string   `json:"structName,omitempty"`
    MethodNameList []string `json:"methodNameList,omitempty"`
}

func NewStructInfo(structName string) *StructInfo {
    return &StructInfo{StructName: structName, MethodNameList: make([]string, 0)}
}

执行结果如下:

在这里插入图片描述

本作品采用《CC 协议》,转载必须注明作者和本文链接
微信公众号:福大大架构师每日一题。最新面试题,涉及golang,rust,mysql,redis,云原生,算法,分布式,网络,操作系统。
讨论数量: 2

学到了。第一眼的反应是要去做语法分析,结果是我想太多了 :joy:

1年前 评论
moonfdd (楼主) 1年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
471
粉丝
21
喜欢
37
收藏
22
排名:457
访问:1.9 万
私信
所有博文
社区赞助商