2013-11-27 45 views
7

使用Go的ast package,我遍歷一個struct的字段列表,像這樣的一個簡單的字符串表示:獲取一個結構字段的類型

type Thing struct { 
    Field1 string 
    Field2 []int 
    Field3 map[byte]float64 
} 

// typ is a *ast.StructType representing the above 
for _, fld := range typ.Fields.List { 
    // get fld.Type as string 
} 

...並想獲得fld.Type的一個簡單的字符串表示,因爲它出現在源代碼中,例如「[] int」或「map [byte] float64」。

ast包field type類型屬性是一個Expr,所以我發現自己使用類型開關進入雜草並專門處理每一種類型 - 當我唯一的目標是讓每個單元格右邊的純字符串字段名稱,這看起來應該更簡單。

有沒有簡單的方法?

+0

你嘗試過'theFileString [fld.Type.Pos():fld.Type.End()]'嗎? – mjibson

回答

11

有兩件事情,你可以在這裏會得到,一個是表達式作爲編譯期間將最終得到解決的型,另一種是在代碼這將決定該類型。

挖掘文檔,我不相信第一個可用。然而,你可以在Node上使用End()Pos()

簡單的例子程序:

package main 

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

func main() { 
    src := ` 
     package foo 

    type Thing struct { 
    Field1 string 
    Field2 []int 
    Field3 map[byte]float64 
    }` 

    fset := token.NewFileSet() 
    f, err := parser.ParseFile(fset, "", src, 0) 

    if err != nil { 
     panic(err) 
    } 

    // hard coding looking these up 
    typeDecl := f.Decls[0].(*ast.GenDecl) 
    structDecl := typeDecl.Specs[0].(*ast.TypeSpec).Type.(*ast.StructType) 
    fields := structDecl.Fields.List 

    for _, field := range fields { 
     typeExpr := field.Type 

     start := typeExpr.Pos() - 1 
     end := typeExpr.End() - 1 

     // grab it in source 
     typeInSource := src[start:end] 

     fmt.Println(typeInSource) 
    } 

} 

此打印:

string 
[]int 
map[byte]float64 

我一起度過這次在golang playground,如果你想惹它。

+0

有幫助,也不幸。 :)文件業務是在我的程序上游,將不得不重組。 –

0

我找到了一種方法來做到這一點,而不使用原始的源代碼進行簡單的會員(不切片,數組或結構)的引用:

  for _, field := range fields { 
       switch field.Type.(type) { 
       case *ast.Ident: 
        stype := field.Type.(*ast.Ident).Name // The type as a string 
        tag = "" 
        if field.Tag != nil { 
         tag = field.Tag.Value //the tag as a string 
        } 
        name := field.Names[0].Name //name as a string 
        ... 

對於非簡單的成員,你只需要另一種情況聲明(IE:case *ast.ArrayType:)。