博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用 Go 的 struct tag 来解析版本号字符串
阅读量:6875 次
发布时间:2019-06-26

本文共 2432 字,大约阅读时间需要 8 分钟。

各类软件的版本号定义虽然都不尽相同,但是其基本原理基本上还是相通的:通过特写的字符对字符串进行分割。我们把这一规则稍作整理,放到 struct tag 中,告诉解析器如何解析,下面就以 semver 为例作个示范:

type SemVersion struct {	Major      int    `version:"0,.1"` Minor int `version:"1,.2"` Patch int `version:"2,+4,-3"` PreRelease string `version:"3,+4"` Build string `version:"4"` }
  1. 其中 struct tag 中的第一段内容表示的是当前字段的一个编号,要求唯一且为数值,0 表示入口;
  2. 后面的是解析规则,可以有多条,以逗号分隔,优先级等同;
  3. 每一条规则的第一个字符为触发条件,之后的数字即为前面的编号,当解析器碰到该字符时,即结束当前字段的解析,跳转到其后面指定的编号字段。

如何实现

首先定义一个表示每个字段的结构:

type struct field {    value  reflect.Value // 指赂字段的值    routes map[byte]int // 解析的跳转规则 }

然后将整个结构体解析到一个 map 中,其键名即为字段的编号:

func getFields(obj interface{}) (map[int]*field, error) { v := reflect.ValueOf(obj) t := v.Type() fields := make(map[int]*field, v.NumField()) for i := 0; i < v.NumField(); i++ { tags := strings.Split(t.Field(i).Tag.Get("version"), ",") if len(tags) < 1 { return nil, errors.New("缺少标签内容") } index, err := strconv.Atoi(tags[0]) if err != nil { return nil, err } if _, found := fields[index]; found { return nil, errors.New("重复的字段编号") } field := &field{routes: make(map[byte]int, 2)} for _, vv := range tags[1:] { n, err := strconv.Atoi(vv[1:]) if err != nil { return nil, err } field.routes[vv[0]] = n } field.value = v.Field(i) fields[index] = field } return fields, nil }

然后通过一个函数将字符串解析到结构中:

func Parse(obj interface{}, ver string) { fields, _ := getFields(obj) start := 0 field := fields[0] for i := 0; i < len(ver)+1; i++ { var nextIndex int if i < len(ver) { // 未结束 index, found := field.routes[ver[i]] if !found { continue } nextIndex = index } switch field.value.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: n, err := strconv.ParseInt(ver[start:i], 10, 64) if err != nil { panic(err) } field.value.SetInt(n) case reflect.String: field.value.SetString(ver[start:i]) default: panic("无效的类型") } i++ // 过滤掉当前字符 start = i field = fields[nextIndex] // 下一个 field } // end for }

之后我们只需要定义各类版本号的相关结构体,然后传给 Parse 就可以了:

// Major_Version_Number.Minor_Version_Number[.Revision_Number[.Build_Number]]type GNUVersion struct {    Major    int    `version:"0,.1"`    Minor    int `version:"1,.2"` Revision int `version:"2, 3"` Build string `version:"3"` } gnu := &GNUVersion{} sem := &SemVersion{} Parse(gnu, "1.2.0 build-1124") Parse(sem, "1.2.0+20160615")

查看完整的实现:

转载于:https://www.cnblogs.com/caixw/p/parse-version-with-go-struct-tag.html

你可能感兴趣的文章
第10件事 向优秀产品学习的学问
查看>>
儿子和女儿——解释器和编译器的区别与联系
查看>>
C#线程
查看>>
C#中的?和??,null和Nullable
查看>>
7-Python与设计模式--适配器模式
查看>>
你真的了解隔离霜吗
查看>>
测试Hadoop2.7.1
查看>>
解决 升级xcode8 后 连接手机出现Could not connect to lockdownd. Exiting.
查看>>
求最小周期串
查看>>
PHP教程
查看>>
keybd_event使用方法
查看>>
http抓包实战之http协议初始、fiddler初识
查看>>
PL/SQL — BULK COLLECT用法
查看>>
史上最全的各类奖学金、各种称号、各种职位中英文对照
查看>>
mtools使用-1
查看>>
Python神器 Jupyter Notebook
查看>>
测试封装
查看>>
C++ string的用法
查看>>
收集的dubbo博客
查看>>
01设计原则--七大设计原则
查看>>