使用go/ast来解析go文件

go/ast是go的type checker 标准包之一(不是编译器的那套工具,编译器用的另外一套),它定义了抽象语法树(AST)的数据类型和操作ast节点的工具

下面我们来看看如何ast树的结构

package main

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

func main() {
	src := `
package main

// 该声明为GenDecl TOK=token.IMPORT
import "fmt"

// 该声明为GenDecl TOK=token.TYPE
type Product struct {
	Name string
}

// 该声明为GenDecl TOK=token.VAR
var product Product

// 该声明为FunDecl
func main() { //test1
	fmt.Println("Hello, World!") //test2
	a := []int{1,2,3}
	a[1],a[2] = 5,6
}
`
	fset := token.NewFileSet() // 位置是相对于节点
	// 用ParseFile把文件解析成*ast.File节点
	f, err := parser.ParseFile(fset, "", src, 0)
	if err != nil {
		panic(err)
	}

	// 打印ast节点
	ast.Print(fset, f)
}

gorm简介[中]

上篇讲到如何用gorm增删改查,但如果涉及一些复杂的操作又想避免使用字符串就需要借助Scopes模块

scopes简介

scopes是需要一个自定义的函数func(db *gorm.DB) *gorm.DB作为参数,这样就可以在不破坏链式语法的情况下自定义操作了

比如我要查询GreekAlphabet表中LatinName是”Alpha”或 “Omega”的条目可以这样

chars := []GreekAlphabet{}
db.Model(&GreekAlphabet{}).Where("latin_name in (?)", []string{"Alpha", "Omega"}).Find(&chars)

因为查询多个字段的值只能用 Where(“field in (?)”, fields) 这种方法,相当于是自己拼接sql语句了,这种方法非常容易出错,所以我们用Scopes封装这部分操作

firstAndLast := func(db *gorm.DB) *gorm.DB {
  return db.Where("latin_name in (?)", []string{"Alpha", "Omega"})
}
chars := []GreekAlphabet{}
db.Model(&GreekAlphabet{}).Scopes(firstAndLast).Find(&chars).Error

这样只要我们对firstAndLast做充足的单元测试就可以让其他人非常安心的使用了,但这样做还是很不灵活,所以下面我们使用offset来制造一个灵活的socpes查询

谈谈go的relfect

go的reflect实现了一个运行时反射,它允许程序操纵任意类型的对象

reflect.TypeOf函数能把对象的类型信息,它返回一个relect.Type

reflect.Type.Field模块可以获得struct或者interface中的字段名,字段类型,字段的tag等信息

reflect.ValueOf可以获得一个对象的值信息,比如它是指针还是实体,值的类型和interface类型下的值,它返回一个reflect.Value

我这里简单谈谈reflect的用法和哪些能做到哪些不能做到

Ps:以下所有代码都包含在这个测试项目


归档 下一页