基础面值

面值是在程序代码中直接表示的值,其它的非零初始值只能由面值常量或常量表达式生成。比如表达式x+2*y的2就是面值,而x和y则不是面值而是标识符。Go语言规范明确定义了基础面值只有整数、浮点数、复数、符文和字符串几种类型。

  1. type BasicLit struct {
  2. ValuePos token.Pos // literal position
  3. Kind token.Token // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING
  4. Value string // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 2.4i, 'a', '\x7f', "foo" or `\m\n\o`
  5. }
  6. func main() {
  7. expr, _ := parser.ParseExpr(`"9527"`)
  8. ast.Print(nil, expr)
  9. }
  10. -------------------------------output-------------------------------
  11. 0 *ast.BasicLit {
  12. 1 . ValuePos: 1
  13. 2 . Kind: STRING
  14. 3 . Value: "\"9527\""
  15. 4 }

标识符面值

  1. type Ident struct {
  2. NamePos token.Pos // identifier position
  3. Name string // identifier name
  4. Obj *Object // denoted object; or nil
  5. }
  6. func main() {
  7. expr, _ := parser.ParseExpr(`x`)
  8. ast.Print(nil, expr)
  9. }
  10. -------------------------------output-------------------------------
  11. 0 *ast.Ident {
  12. 1 . NamePos: 1
  13. 2 . Name: "x"
  14. 3 . Obj: *ast.Object {
  15. 4 . . Kind: bad
  16. 5 . . Name: ""
  17. 6 . }
  18. 7 }

ast.Object是一个相对复杂的结构,其中Kind用于描述标识符的类型:

  1. const (
  2. Bad ObjKind = iota // for error handling
  3. Pkg // package
  4. Con // constant
  5. Typ // type
  6. Var // variable
  7. Fun // function or method
  8. Lbl // label
  9. )

Bad表示未知的类型,其它的分别对应Go语言中包、常量、类型、变量、函数和标号等语法结构。

复合面值

在基础面值,我们已经见过整数、浮点数、复数、符文和字符串等一些简单的面值。除了基础面值之外,还有结构体面值、map面值和函数面值等。本节讨论复合面值的语法树表示。

函数面值

  1. func main() {
  2. expr, _ := parser.ParseExpr(`func(){}`)
  3. ast.Print(nil, expr)
  4. }
  5. ---------------------------output-------------------------
  6. 0 *ast.FuncLit {
  7. 1 . Type: *ast.FuncType {
  8. 2 . . Func: 1
  9. 3 . . Params: *ast.FieldList {
  10. 4 . . . Opening: 5
  11. 5 . . . Closing: 6
  12. 6 . . }
  13. 7 . }
  14. 8 . Body: *ast.BlockStmt {
  15. 9 . . Lbrace: 7
  16. 10 . . Rbrace: 8
  17. 11 . }
  18. 12 }

函数面值的语法树由ast.FuncLit结构体表示,其中再由Type成员表示类型,Body成员表示函数体语句。
我们可以对比下
ast.FuncLit和ast.FuncDecl结构体的差异:

  1. type FuncLit struct {
  2. Type *FuncType // function type
  3. Body *BlockStmt // function body
  4. }
  5. type FuncDecl struct {
  6. Doc *CommentGroup // associated documentation; or nil
  7. Recv *FieldList // receiver (methods); or nil (functions)
  8. Name *Ident // function/method name
  9. Type *FuncType // function signature: parameters, results, and position of "func" keyword
  10. Body *BlockStmt // function body; or nil for external (non-Go) function
  11. }

复合类型面值语法

复合型面值的语法树通过ast.CompositeLit表示:

  1. type CompositeLit struct {
  2. Type Expr // literal type; or nil
  3. Lbrace token.Pos // position of "{"
  4. Elts []Expr // list of composite elements; or nil
  5. Rbrace token.Pos // position of "}"
  6. Incomplete bool // true if (source) expressions are missing in the Elts list
  7. }

其中ast.CompositeLit.Type对应复合类型的表达式,然后ast.CompositeLit.Elts是复合类型初始元素列表。初始元素列表可以是普通的值,也可能是Key-Value下标和值对,而且初始值还可能是其它的复合面值。

数组和切片面值

  1. func main() {
  2. expr, _ := parser.ParseExpr(`[...]int{1,2:3}`)
  3. ast.Print(nil, expr)
  4. }
  5. ---------------------------output-------------------------
  6. 0 *ast.CompositeLit {
  7. 1 . Type: *ast.ArrayType {
  8. 2 . . Lbrack: 1
  9. 3 . . Len: *ast.Ellipsis {
  10. 4 . . . Ellipsis: 2
  11. 5 . . }
  12. 6 . . Elt: *ast.Ident {
  13. 7 . . . NamePos: 6
  14. 8 . . . Name: "int"
  15. 9 . . . Obj: *ast.Object {
  16. 10 . . . . Kind: bad
  17. 11 . . . . Name: ""
  18. 12 . . . }
  19. 13 . . }
  20. 14 . }
  21. 15 . Lbrace: 9
  22. 16 . Elts: []ast.Expr (len = 2) {
  23. 17 . . 0: *ast.BasicLit {
  24. 18 . . . ValuePos: 10
  25. 19 . . . Kind: INT
  26. 20 . . . Value: "1"
  27. 21 . . }
  28. 22 . . 1: *ast.KeyValueExpr {
  29. 23 . . . Key: *ast.BasicLit {
  30. 24 . . . . ValuePos: 12
  31. 25 . . . . Kind: INT
  32. 26 . . . . Value: "2"
  33. 27 . . . }
  34. 28 . . . Colon: 13
  35. 29 . . . Value: *ast.BasicLit {
  36. 30 . . . . ValuePos: 14
  37. 31 . . . . Kind: INT
  38. 32 . . . . Value: "3"
  39. 33 . . . }
  40. 34 . . }
  41. 35 . }
  42. 36 . Rbrace: 15
  43. 37 . Incomplete: false
  44. 38 }

复合面值语法树由ast.CompositeLit结构体表示,其中ast.CompositeLit.Type成员为ast.ArrayType表示这是数组或切片类型(如果没有长度信息则为切片类型,否则就是数组),而ast.CompositeLitElts成员则是元素的值。初始元素是一个[]ast.Expr类型的切片,每个元素依然是一个表达式。数组的第一个元素是ast.BasicLit类型,表示这是一个基础面值类型。数组的第二个元素是ast.KeyValueExpr方式指定的,其中Key对应的数组下标是2,Value对应的值为3。

数组和切片语法的最大差别是数组有长度信息。在这个例子中数组是通过…省略号表达式自动计算数组的长度,在语法树中对应的是ast.Ellipsis表达式类型。如果ast.ArrayType结构体中的Len成员是空指针,则表示这是一个切片类型,否则对应可以生成数组长度的表达式。

结构体面值

  1. func main() {
  2. expr, _ := parser.ParseExpr(`struct{X int}{X:1}`)
  3. ast.Print(nil, expr)
  4. }
  5. ---------------------------output-------------------------
  6. 0 *ast.CompositeLit {
  7. 1 . Type: *ast.StructType {...}
  8. 32 . Lbrace: 14
  9. 33 . Elts: []ast.Expr (len = 1) {
  10. 34 . . 0: *ast.KeyValueExpr {
  11. 35 . . . Key: *ast.Ident {
  12. 36 . . . . NamePos: 15
  13. 37 . . . . Name: "X"
  14. 38 . . . }
  15. 39 . . . Colon: 16
  16. 40 . . . Value: *ast.BasicLit {
  17. 41 . . . . ValuePos: 17
  18. 42 . . . . Kind: INT
  19. 43 . . . . Value: "1"
  20. 44 . . . }
  21. 45 . . }
  22. 46 . }
  23. 47 . Rbrace: 18
  24. 48 . Incomplete: false
  25. 49 }

结构体面值依然是通过ast.CompositeLit结构体描述。结构体中成员的初始化通过ast.KeyValueExpr结构体初始化,Key部分为X表示成员名字,Value部分为X成员的初始值。
当然,结构体的初始化也可以不声明成员的名字:

  1. func main() {
  2. expr, _ := parser.ParseExpr(`struct{X int}{1}`)
  3. ast.Print(nil, expr)
  4. }
  5. ---------------------------output-------------------------
  6. 33 . Elts: []ast.Expr (len = 1) {
  7. 34 . . 0: *ast.BasicLit {
  8. 35 . . . ValuePos: 15
  9. 36 . . . Kind: INT
  10. 37 . . . Value: "1"
  11. 38 . . }
  12. 39 . }

只有一个元素是通过ast.BasicLit对应的基础面值表示,对应结构体的第一个成员。

map面值

  1. func main() {
  2. expr, _ := parser.ParseExpr(`map[int]int{1:2}`)
  3. ast.Print(nil, expr)
  4. }
  5. ---------------------------output-------------------------
  6. 18 . Elts: []ast.Expr (len = 1) {
  7. 19 . . 0: *ast.KeyValueExpr {
  8. 20 . . . Key: *ast.BasicLit {
  9. 21 . . . . ValuePos: 13
  10. 22 . . . . Kind: INT
  11. 23 . . . . Value: "1"
  12. 24 . . . }
  13. 25 . . . Colon: 14
  14. 26 . . . Value: *ast.BasicLit {
  15. 27 . . . . ValuePos: 15
  16. 28 . . . . Kind: INT
  17. 29 . . . . Value: "2"
  18. 30 . . . }
  19. 31 . . }
  20. 32 . }

map的初始值只能通过ast.KeyValueExpr对应的键值对表示,因为缺少了key无法定位值对应的下标位置。