Parsing 使用“go/parser”检查表达式是否为自定义类型
处境 编写代码生成器,检查结构的字段并使用结构标记添加验证函数 问题 这里我需要检查类型字段是否为自定义类型 即 以下不是自定义类型Parsing 使用“go/parser”检查表达式是否为自定义类型,parsing,go,types,generated-code,Parsing,Go,Types,Generated Code,处境 编写代码生成器,检查结构的字段并使用结构标记添加验证函数 问题 这里我需要检查类型字段是否为自定义类型 即 以下不是自定义类型 int, []int,*int,[]Integer,map[string]PhoneNumber 但以下是自定义类型 Integer,PhoneNumber,*PhoneNumber 我想我可以使用如下函数来实现,这些函数可以查找精确匹配,并可以添加map、[]支持 func isBuiltInType(typ string) bool { swit
int, []int,*int,[]Integer,map[string]PhoneNumber
但以下是自定义类型
Integer,PhoneNumber,*PhoneNumber
我想我可以使用如下函数来实现,这些函数可以查找精确匹配,并可以添加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
}
但是,有没有更好的方法使用parse.parsexpr等来实现这一点呢?对于任何类型的可靠结果,您都希望使用Go/types包使用Go的类型检查器。它的使用并不简单,但在上有一篇有用的介绍性文章 我编写了一个示例程序,这样您就可以看到预期的结果。重要的一点是isBasic函数,其余的只是使其可执行的样板文件。特别是,AST遍历是针对特定样本源代码进行硬编码的。我想你已经有了自己的代码 关键是types.Info结构包含实现自己的逻辑所需的所有类型信息 我发现,在处理代码生成和/或解析加载程序包时,它是完整类型信息所必需的
您是要检查类型声明还是源中的任意值?ParseExpr本身无法为您提供实际的类型,因为表达式没有任何类型信息。如果您展示一个需要确定类型的示例,可能会有所帮助。您所称的自定义类型也可能有您在此处列出的任何类型作为其基础类型。@JimB struct field由字段名、字段类型和结构标记三部分组成。我需要检查字段类型是否正确。可以将自定义类型的基础类型设为内置类型。由于我正在编写代码,以便为嵌套检查的结构生成验证函数,因此如果实现了validater,我需要在字段上调用Validate。fBetter方法可能是,在解析源代码后,收集实现要调用的方法的所有类型,在本例中,该方法似乎类似于Validate error。然后,当您为某些结构生成验证代码并检查其字段的类型时,请检查给定类型是否包含在实现要生成调用的方法的集合类型中……请记住,可能确实存在一个类型,这就是为什么我需要检查它是否为任何类型,但为内置类型,阿拉等。
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("")
}