编写golang编写注解的静态代码增强器/生成器的方法
发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,本篇内容介绍了"编写golang编写注解的静态代码增强器/生成器的方法"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读
千家信息网最后更新 2026年11月02日编写golang编写注解的静态代码增强器/生成器的方法
本篇内容介绍了"编写golang编写注解的静态代码增强器/生成器的方法"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
Spring
Spring的主要特性:1. 控制反转(Inversion of Control, IoC)2. 面向容器3. 面向切面(AspectOriented Programming, AOP)源码gitee地址:https://gitee.com/ioly/learning.gooop原文链接:https://my.oschina.net/ioly
目标
参考spring boot常用注解,使用golang编写"基于注解的静态代码增强器/生成器"
子目标(Day 7)
因为struct/field/method的扫描是关键,因此今天针对这块做了单元测试
common/Tokens.go:修复MatchBasicType方法的正则匹配bug。其实func类型的DataType也没考虑到,但现在暂时可以用type alias规避,先不追求完美吧。
scanner/IStructScanner.go: 修复若干细节, 并添加返回类型的扫描
scanner/IStructScanner_test.go:struct扫描器的单元测试
common/Tokens.go
修复MatchBasicType方法的正则匹配bug。其实func类型的DataType也没考虑到,但现在暂时可以用type alias规避,先不追求完美吧。
func (me *tTokens) MatchBasicType(s string) (bool, string) { list := []string{ "int", "string", "bool", "byte", "int32", "int64", "uint32", "uint64", "float32", "float64", "int8", "uint8", "int16", "uint16", `time\.Time`, } for _, it := range list { if ok, t := me.MatchRegexp(s, "^"+it+`(\s+|$)`); ok { return true, strings.TrimSpace(t) } } return false, ""}scanner/IStructScanner.go
修复若干细节, 并添加返回类型的扫描
package scannerimport ( "errors" "learning/gooop/spring/autogen/common" "learning/gooop/spring/autogen/domain" "regexp" "strings")type IStructScanner interface { ScanStruct(file *domain.CodeFileInfo)}type tStructScanner intfunc (me *tStructScanner) ScanStruct(file *domain.CodeFileInfo) { bInStruct := false vStructs := []*domain.StructInfo{nil} for lineNO, line := range file.CleanLines { if bInStruct { // end? if gStructEndRegexp.MatchString(line) { me.scanMethod(vStructs[0], lineNO+1) file.AppendStruct(vStructs[0]) bInStruct = false vStructs[0] = nil continue } // in struct block ok, fname, ftype := me.scanField(line) if ok { vStructs[0].AppendField(lineNO, fname, ftype) } } else { // not in struck block // matching start? if gStructStartRegexp.MatchString(line) { bInStruct = true ss := gStructStartRegexp.FindStringSubmatch(line) vStructs[0] = domain.NewStructInfo() vStructs[0].LineNO = lineNO vStructs[0].CodeFile = file vStructs[0].Name = ss[1] continue } } }}func (me *tStructScanner) scanField(line string) (ok bool, fldName string, fldType string) { if !gFieldStartRegexp.MatchString(line) { return false, "", "" } t := line s1 := gFieldStartRegexp.FindString(t) fldName = strings.TrimSpace(s1) t = t[len(s1):] b2, s2 := common.Tokens.MatchDataType(t) if !b2 { return false, "", "" } fldType = strings.TrimSpace(s2) return true, fldName, fldType}func (me *tStructScanner) scanMethod(stru *domain.StructInfo, fromLineNO int) { for i, limit := fromLineNO, len(stru.CodeFile.CleanLines); i < limit; i++ { line := stru.CodeFile.CleanLines[i] if !gMethodStartRegex.MatchString(line) { continue } ss := gMethodStartRegex.FindStringSubmatch(line) // declare declare := ss[0] offset := len(declare) // receiver receiver := ss[1] if receiver != stru.Name { continue } method := domain.NewMethodInfo() // name method.Name = ss[2] // method input args e, args := me.scanMethodArgs(method, strings.TrimSpace(line[offset:])) if e != nil { panic(e) } offset += len(args) // method return args e = me.scanReturnArgs(method, strings.TrimSpace(line[offset:])) if e != nil { panic(e) } // end scan method stru.AppendMethod(method) }}func (me *tStructScanner) scanMethodArgs(method *domain.MethodInfo, s string) (error, string) { t := s offset := 0 for { // name b1, s1 := common.Tokens.MatchRegexp(t, `^\w+(\s*,\s*\w+)?\s+`) if !b1 { break } argNames := strings.TrimSpace(s1) offset += len(s1) t = s[offset:] // data type b2, s2 := common.Tokens.MatchDataType(t) if !b2 { return gInvalidMethodArgs, "" } argDataType := s2 offset += len(s2) t = s[offset:] for _, it := range strings.Split(argNames, ",") { method.AppendArgument(it, argDataType) } // ,\s+ b3, s3 := common.Tokens.MatchRegexp(t, `\s*,\s*`) if !b3 { break } offset += len(s3) t = s[offset:] } b4, s4 := common.Tokens.MatchRegexp(t, `^\s*\)`) if !b4 { return errors.New("expecting right bracket"), "" } offset += len(s4) return nil, s[0:offset]}func (me *tStructScanner) scanReturnArgs(method *domain.MethodInfo, s string) error { // no args? if gMethodEndRegexp.MatchString(s) { return nil } // args start t := s b1, s1 := common.Tokens.MatchRegexp(t, `\s*\(\s*`) if !b1 { return errors.New("expecting left bracket") } t = t[len(s1):] // unnamed args? b2, s2 := common.Tokens.MatchDataType(t) if b2 { t = t[len(s2):] method.AppendUnnamedReturn(s2) // more unnamed args? for { b3, s3 := common.Tokens.MatchRegexp(t, `^\s*,\s*`) if !b3 { break } t = t[len(s3):] b4, s4 := common.Tokens.MatchDataType(t) if !b4 { return errors.New("expecting data type") } t = t[len(s4):] method.AppendUnnamedReturn(s4) } } else { // named args? for { // name b3, s3 := common.Tokens.MatchIdentifier(t) if !b3 { return errors.New("expecting identifier") } t = t[len(s3):] // \s+ b4, s4 := common.Tokens.MatchSpaces(t) if !b4 { return errors.New("expecting spaces") } t = t[len(s4):] // type b5, s5 := common.Tokens.MatchDataType(t) if !b5 { return errors.New("expecting data type") } t = t[len(s5):] // more? b6, s6 := common.Tokens.MatchRegexp(t, `^\s*,\s*`) if b6 { // yes more t = t[len(s6):] } else { // no more break } } } // arguments end b7, _ := common.Tokens.MatchRegexp(t, `^\s*\)\s*`) if !b7 { return errors.New("expecting end of arguments") } return nil}var gStructStartRegexp = regexp.MustCompile(`^\s*type\s+(\w+)\s+struct\s+\{`)var gStructEndRegexp = regexp.MustCompile(`^\s*}`)var gFieldStartRegexp = regexp.MustCompile(`^\s*\w+\s+`)var gMethodStartRegex = regexp.MustCompile(`^\s*func\s+\(\s*\w+\s+\*?(\w+)\s*\)\s+(\w+)\s*\(`)var gInvalidMethodArgs = errors.New("invalid method arguments")var gMethodEndRegexp = regexp.MustCompile(`^\s*\{`)var DefaultStructScanner IStructScanner = new(tStructScanner)scanner/IStructScanner_test.go
struct扫描器的单元测试
package scannerimport ( "encoding/json" "learning/gooop/spring/autogen/domain" "strings" "testing")func Test_StructScan(t *testing.T) { s := `type _mystruct struct {` t.Log(gStructStartRegexp.MatchString(s)) code := `type StructInfo struct { LineNO int Name string CodeFile *CodeFileInfo Fields []*FieldInfo Methods []*MethodInfo Annotations []*AnnotationInfo}func NewStructInfo() *StructInfo { it := new(StructInfo) it.Fields = []*FieldInfo{} it.Methods = []*MethodInfo{} it.Annotations = []*AnnotationInfo{} return it}func (me *StructInfo) AppendField(lineNO int, name string, dataType string) { fld := NewFieldInfo() fld.Struct = me fld.LineNO = lineNO fld.Name = name fld.DataType = dataType me.Fields = append(me.Fields, fld)}func (me *StructInfo) AppendMethod(method *MethodInfo) { me.Methods = append(me.Methods, method)}func (me *StructInfo) AppendAnnotation(ant *AnnotationInfo) { me.Annotations = append(me.Annotations, ant)}` file := domain.NewCodeFileInfo() file.CleanLines = strings.Split(code, "\n") DefaultStructScanner.ScanStruct(file) file.CleanLines = nil j, e := json.MarshalIndent(file.Structs, "", " ") if e != nil { panic(e) } t.Log(string(j))}测试输出
API server listening at: [::]:36077=== RUN Test_StructScan IStructScanner_test.go:12: true IStructScanner_test.go:58: [ { "LineNO": 1, "Name": "StructInfo", "Fields": [ { "LineNO": 2, "Name": "LineNO", "DataType": "int", "Annotations": [] }, { "LineNO": 3, "Name": "Name", "DataType": "string", "Annotations": [] }, { "LineNO": 4, "Name": "CodeFile", "DataType": "*CodeFileInfo", "Annotations": [] }, { "LineNO": 5, "Name": "Fields", "DataType": "[]*FieldInfo", "Annotations": [] }, { "LineNO": 6, "Name": "Methods", "DataType": "[]*MethodInfo", "Annotations": [] }, { "LineNO": 7, "Name": "Annotations", "DataType": "[]*AnnotationInfo", "Annotations": [] } ], "Methods": [ { "LineNO": 0, "Name": "AppendField", "Arguments": [ { "Name": "lineNO", "DataType": "int" }, { "Name": "name", "DataType": "string" }, { "Name": "dataType", "DataType": "string" } ], "Annotations": [], "Returns": [] }, { "LineNO": 0, "Name": "AppendMethod", "Arguments": [ { "Name": "method", "DataType": "*MethodInfo" } ], "Annotations": [], "Returns": [] }, { "LineNO": 0, "Name": "AppendAnnotation", "Arguments": [ { "Name": "ant", "DataType": "*AnnotationInfo" } ], "Annotations": [], "Returns": [] } ], "Annotations": [] } ]--- PASS: Test_StructScan (0.01s)PASSDebugger finished with exit code 0"编写golang编写注解的静态代码增强器/生成器的方法"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!
方法
注解
类型
测试
代码
生成器
静态
增强器
生成
单元
内容
扫描器
更多
正则
目标
知识
细节
输出
实用
学有所成
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
中智农互联网科技
今日互联网科技
关于新基建和互联网科技
互联网科技股票
齐家互联网科技
西安互联网科技公司
睿民互联网科技
深圳天众互联网科技公司
互联网科技网站
居家互联网科技有限公司
广西拼得多互联网科技有限公司
开启互联网科技时代小说
互联网科技产品
互联网科技革命什么开始
明优互联网科技有限公司
张召忠谈中国互联网科技
本届互联网大会上的黑科技
工业互联网科技成果转化
同城互联网络科技
互联网科技创新方面的资料
苏州找大状互联网科技有限公司
易互联网科技有限公司
互联网与未来科技
奔汉互联网科技
互联网科技公司有哪些
上海京穆互联网科技有限公司
全球科技与互联网公司市值变化
恒生科技指数 中概互联网
互联网企业和网络科技有限公司
银川新华互联网科技学校招聘