Skip to content

gomelon/meta

Repository files navigation

Meta

本库是为了实现Golang的元编程(Metaprogramming)。

元编程是一种编程技术,使计算机程序能够将其他程序视为其数据。 这意味着一个程序可以被设计为读取、生成、分析或转换其他程序,甚至在运行时修改自身。 在某些情况下,这使程序员可以最大限度地减少表达解决方案的代码行数,从而减少开发时间。

目标

  • 消除样板代码(Boilerplate code)
  • 可以面向切面编程(Aspect-Oriented Programming)

应用场景包括但不限于

  • 通过方法签名生成数据库访问实现(类Spring Data), 参看sqlmap
  • 缓存切面
  • 事务切面
  • 熔断及降级切面
  • 链路跟踪切面
  • 自动注入,参看autowire

原理

很多编程语言都支持元编程,例如Java,主要通过反射加注解。

Golang通过Tag加反射也能进行元编程,但有以下缺点

  1. Tag仅支持结构成员
  2. 反射容易受语言本身限制
  3. 反射容易对性能产生负影响
  4. 反射只能在运行时才能发现问题

本库选择使用代码生成的方式

  1. 使用标准库asttypes包解析代码及注释
  2. 使用标准库text/template包作为模版进行代码生成
  3. 封装常用代码解析函数作为模版的自定义函数,简化模版编写复杂度

功能

  1. 解析Golang源码及注释
  2. 丰富的代码解析类模版函数
  3. 高度可定制,用户可以自定义模版函数及模版,用于生成自己想要的程序

使用

简单示例

本例子演示为注释有//+iface.Ifacestruct生成接口

//SomeStruct
//+iface.Iface
type SomeStruct struct {
}

func (s *SomeStruct) PublicMethod(ctx context.Context, id int64) (string, error) {
	return "nil", nil
}

func (s *SomeStruct) privateMethod(ctx context.Context, time time.Time) (int32, error) {
	return 0, nil
}

//NoneMethodStruct
//+iface.Iface
type NoneMethodStruct struct {
}
// define template
var tplText = `
{{range $struct := structs|filterByMeta "+iface.Iface"}}
    {{$decorator := print $struct.Name "AOPIface"}}
    type {{$decorator}} interface {
    {{range $method := $struct|methods}}
        {{if $method|exported}}
            {{$method|declare}}
        {{end}}
    {{end}}
    }
{{end}}
`

func Genearte() {
	//scan current mod code
	err := ScanCurrentMod().
		// register template
		TemplateText(tplText).
		// the package path must regex match the rule
		RegexOr("testdata").
		// you can add more generator
		And().
		// generate code
		Generate()

	if err != nil {
		fmt.Println(err.Error())
		return
	}
}
// Code generated by meta. DO NOT EDIT.

package testdata

import (
	"context"
)

type NoneMethodStructAOPIface interface {
}

type SomeStructAOPIface interface {
	PublicMethod(ctx context.Context, id int64) (string, error)
}

复杂示例

本例子演示为注释//+sqlmap.Mapperinterface生成数据库访问实现(类Spring Data)

  • 待生成实现的interface,user.go
    • 为方法FindByBirthdayGTE按方法签名生成数据库访问实现
    • 为方法FindByBirthdayGTE2按方法上的+sqlmap.Selectquery参数对应的sql生成数据库访问实现
//UserDao
//+sqlmap.Mapper Table=`user` Dialect="mysql"
type UserDao interface {

	// FindByBirthdayGTE
	FindByBirthdayGTE(ctx context.Context /*sql:param ctx*/, time time.Time) ([]*User, error)

	//FindByBirthdayGTE2
	/*+sqlmap.Select Query="select * from `user` where birthday >= :time"*/
	FindByBirthdayGTE2(ctx context.Context /*sql:param ctx*/, time time.Time) ([]*User, error)
}
package testdata

import (
	"context"
	"time"

	"github.com/gomelon/melon/data"
)

var _ UserDao = &UserDaoSQLImpl{}

type UserDaoSQLImpl struct {
	_tm *data.SQLTXManager
}

func NewUserDaoSQLImpl(_tm *data.SQLTXManager) *UserDaoSQLImpl {
	return &UserDaoSQLImpl{
		_tm: _tm,
	}
}

func (_impl *UserDaoSQLImpl) FindByBirthdayGTE(ctx context.Context, time time.Time) ([]*User, error) {
	_sql := "SELECT id, name, gender, birthday, created_at FROM `user` WHERE (`birthday` >= ?)"
	_rows, _err := _impl._tm.OriginTXOrDB(ctx).
		Query(_sql, time)

	var _items []*User
	if _err != nil {
		return _items, _err
	}

	defer _rows.Close()

	if !_rows.Next() {
		return _items, _rows.Err()
	}

	for _rows.Next() {
		_item := &User{}
		_err = _rows.Scan(&_item.Id, &_item.Name, &_item.Gender, &_item.Birthday, &_item.CreatedAt)
		if _err != nil {
			return _items, _err
		}
		_items = append(_items, _item)
	}
	return _items, nil
}

func (_impl *UserDaoSQLImpl) FindByBirthdayGTE2(ctx context.Context, time time.Time) ([]*User, error) {
	_sql := "select id, name, gender, birthday, created_at from `user` where birthday >= ?"
	_rows, _err := _impl._tm.OriginTXOrDB(ctx).
		Query(_sql, time)

	var _items []*User
	if _err != nil {
		return _items, _err
	}

	defer _rows.Close()

	if !_rows.Next() {
		return _items, _rows.Err()
	}

	for _rows.Next() {
		_item := &User{}
		_err = _rows.Scan(&_item.Id, &_item.Name, &_item.Gender, &_item.Birthday, &_item.CreatedAt)
		if _err != nil {
			return _items, _err
		}
		_items = append(_items, _item)
	}
	return _items, nil
}

主要函数

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published