【问题标题】:check if an expression is a custom type using "go/parser"使用“go/parser”检查表达式是否是自定义类型
【发布时间】:2018-03-10 15:19:50
【问题描述】:

情况

编写代码生成器,检查结构的字段并使用结构标签添加验证函数

问题

这里需要检查type字段是否为自定义类型

即,

以下不是自定义类型

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

但以下是自定义类型

Integer,PhoneNumber,*PhoneNumber

我想我可以使用以下函数来查找完全匹配并可能添加地图,[] 支持

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.ParseExpr

【问题讨论】:

  • 您是要检查类型声明还是源中的任意值? ParseExpr 不能单独为您提供实际类型,因为表达式没有任何类型信息。如果您展示了一个需要确定类型的示例,这可能会有所帮助。此外,您所称的“自定义类型”可能具有您在此处列出的任何类型作为其基础类型。
  • @JimB struct 字段包含三个部分 field namefield typestruct tag。我需要检查 field type 。让 custom type 具有底层类型作为内置是可以的在类型。由于我正在编写代码来生成 Validate 函数以用于嵌套检查的结构,因此如果它实现 validater f,我需要在字段上调用 ​​Validate
  • 更好的方法可能是,在解析源代码后,收集所有实现您要调用的方法的类型,在这种情况下,它似乎类似于Validate() error。然后,当您为某些结构生成验证代码并检查其字段的类型时,检查给定类型是否包含在实现您打算生成调用的方法的收集类型集中。
  • 完全正确,这就是为什么我需要检查它是否存在但内置类型、arra 等。

标签: parsing go types generated-code


【解决方案1】:

对于任何类型的可靠结果,您都需要使用 go/types 包使用 Go 的类型检查器。使用起来并不简单,但在https://golang.org/s/types-tutorial 有一篇很有帮助的介绍性文章。

我整理了一个示例程序,因此您可以看到会发生什么。重要的一点是isBasic 函数,其余的只是使其可执行的样板。特别是,AST 遍历是针对特定示例源代码进行硬编码的。我想你已经有了自己的代码。

关键是types.Info结构包含实现自己的逻辑所需的所有类型信息。

我发现 github.com/fatih/astrewritegolang.org/x/tools/go/loader 在处理代码生成和/或解析时很有帮助(对于完整的类型信息,加载程序包是一种必需的)。

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("")
}

【讨论】:

    猜你喜欢
    • 2014-08-14
    • 1970-01-01
    • 2014-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-19
    • 2018-06-08
    • 2022-07-18
    相关资源
    最近更新 更多