简体   繁体   English

使用“ go / parser”检查表达式是否为自定义类型

[英]check if an expression is a custom type using “go/parser”

Situation 情况

writing a code generator that checks fields of a struct and add validation functions using struct tags 编写代码生成器以检查结构的字段并使用struct标签添加验证功能

Problem 问题

Here I need to check if the type field is a custom type or not 在这里,我需要检查类型字段是否为自定义类型

ie,

Following are not custom types 以下不是自定义类型

int, []int,*int,[]Integer,map[string]PhoneNumber 

But the following are custom type 但是以下是自定义类型

Integer,PhoneNumber,*PhoneNumber

I think I can do it using functions like the following that looks for exact match and may add map,[] support 我想我可以使用以下函数来查找确切匹配并添加map []支持

func isBuiltInType(typ string) bool {
    switch typ {
            case "bool", "byte", "complex128", "complex64", "error": 
            case "float32", "float64":
            case "int", "int16", "int32", "int64", "int8":
            case "rune", "string":
            case "uint", "uint16", "uint32", "uint64", "uint8", "uintptr":
            default:
                return false
    }
    return true
}

But is there a better way to do it using parse.ParseExpr etc 但是有没有更好的方法使用parse.ParseExpr等来做到这parse.ParseExpr

For any kind of reliable result you will want to involve Go's type checker using the go/types package. 对于任何可靠的结果,您都需要使用go / types包来使用Go的类型检查器。 It is not trivial to use, but there is a helpful introductory article at https://golang.org/s/types-tutorial . 使用它并不简单,但是在https://golang.org/s/types-tutorial上有一篇很有帮助的介绍性文章。

I threw together an example program, so you can see what to expect. 我整理了一个示例程序,因此您可以看到期望的结果。 The important bit is the isBasic function, the rest is just boilerplate to make it executable. 重要的一点是isBasic函数,其余的只是使它可执行的样板。 In particlar, the AST traversal is hardcoded for the specific sample source code. 特别是,AST遍历针对特定的示例源代码进行了硬编码。 I presume you already have your own code in place for that. 我想您已经为此拥有了自己的代码。

The key point is that the types.Info structure contains all the type information you need to implement your own logic. 关键在于, types.Info结构包含实现自己的逻辑所需的所有类型信息。

I found github.com/fatih/astrewrite and golang.org/x/tools/go/loader helpful when dealing with code generation and/or parsing (the loader package is kind of required for complete type information). 我发现github.com/fatih/astrewritegolang.org/x/tools/go/loader代码生成和/或解析(装载包是种需要完整的类型信息)时也有帮助。

https://play.golang.org/p/A9hdPy-Oy- https://play.golang.org/p/A9hdPy-Oy-

package main

import (
    "bufio"
    "fmt"
    "go/ast"
    "go/parser"
    "go/token"
    "go/types"
    "log"
    "strings"
)

var src = strings.TrimSpace(`
package main

type T struct{}

func f() {
    var _ T
    var _ *T

    var _ int
    var _ *int
    var _ **int
    var _ []int
    var _ []T
    var _ map[string]int
    var _ map[string]T
}
`)

func main() {
    // Parse source
    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, "src.go", src, 0)
    if err != nil {
            log.Fatal(err)
    }

    // Run type checker
    info := types.Info{Types: make(map[ast.Expr]types.TypeAndValue)}

    _, err = (&types.Config{}).Check("mypkg", fset, []*ast.File{f}, &info)
    if err != nil {
            log.Fatal(err)
    }

    printSrc()

    // Inspect variable types in f()
    for _, varDecl := range f.Decls[1].(*ast.FuncDecl).Body.List {
            value := varDecl.(*ast.DeclStmt).Decl.(*ast.GenDecl).Specs[0].(*ast.ValueSpec)

            pos := fset.Position(value.Type.Pos())
            typ := info.Types[value.Type].Type

            fmt.Println(pos, "basic:", isBasic(typ))
    }
}

func isBasic(t types.Type) bool {
    switch x := t.(type) {
    case *types.Basic:
            return true
    case *types.Slice:
            return true
    case *types.Map:
            return true
    case *types.Pointer:
            return isBasic(x.Elem())
    default:
            return false
    }
}

func printSrc() {
    s := bufio.NewScanner(strings.NewReader(src))
    for i := 1; s.Scan(); i++ {
            fmt.Printf("%2d: %s\n", i, s.Text())
    }
    fmt.Println("")
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM