[英]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/astrewrite和golang.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.