使用 Go 的 struct tag 来解析版本号字符串
各类软件的版本号定义虽然都不尽相同,但是其基本原理基本上还是相通的:通过特写的字符对字符串进行分割。我们把这一规则稍作整理,放到 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"`
}
- 其中 struct tag 中的第一段内容表示的是当前字段的一个编号,要求唯一且为数值,0 表示入口;
- 后面的是解析规则,可以有多条,以逗号分隔,优先级等同;
- 每一条规则的第一个字符为触发条件,之后的数字即为前面的编号,当解析器碰到该字符时,即结束当前字段的解析,跳转到其后面指定的编号字段。
如何实现
首先定义一个表示每个字段的结构:
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")
使用 Go 的 struct tag 来解析版本号字符串的更多相关文章
- 【linux】U-BOOT与linux kernel通信: struct tag
欢迎转载,转载时需保留作者信息. 邮箱:tangzhongp@163.com 博客园地址:http://www.cnblogs.com/embedded-tzp Csdn博客地址:http://b ...
- 引用 U-boot给kernel传参数和kernel读取参数—struct tag
引用 清风徐徐 的 U-boot给kernel传参数和kernel读取参数—struct tag U-boot会给Linux Kernel传递很多参数,如:串口,RAM,videofb等.而Linux ...
- Go语言中的struct tag
有时在Go的结构体定义时会看到这样的形式: type User struct { UserId int `json:"user_id" bson:"b_user_id&q ...
- java后台处理解析json字符串的两种方式
简单说一下背景 上次后端通过模拟http请求百度地图接口,得到的是一个json字符串,而我只需要其中的某个key对应的value. 当时我是通过截取字符串取的,后来觉得不太合理,今天整理出了两种处理解 ...
- js中解析json对象:JSON.parse()用于从一个字符串中解析出json对象, JSON.stringify()用于从一个对象解析出字符串。
JSON.parse()用于从一个字符串中解析出json对象. var str = '{"name":"huangxiaojian","age&quo ...
- 使用 dynamic 标记解析JSON字符串 JDynamic :支持Json反序列化为Dynamic对象
使用 dynamic 标记解析JSON字符串 http://www.cnblogs.com/taotaodetuer/p/4171327.html 1 string jsonStr = " ...
- 字串符相关 split() 字串符分隔 substring() 提取字符串 substr()提取指定数目的字符 parseInt() 函数可解析一个字符串,并返回一个整数。
split() 方法将字符串分割为字符串数组,并返回此数组. stringObject.split(separator,limit) 我们将按照不同的方式来分割字符串: 使用指定符号分割字符串,代码如 ...
- jq 解析josn字符串
1. var obj = jQuery.parseJSON("${ruleModel.rules}"); 2. var obj = eval("("+" ...
- json解析json字符串时候,数组必须对应jsonObjectArray,不能对应JsonObject。否则会解析错误。
json第三方解析json字符串时候,json数组必须对应jsonObjectArray,不能对应JsonObject.->只要是[]开头的都是json数组字符串,就要用jsonArray解析 ...
随机推荐
- git 上传项目
参考:https://blog.csdn.net/qq_28304687/article/details/69959238?fps=1&locationNum=8 第一部分 初次上传 1.先在 ...
- 洛谷P4556 [Vani有约会]雨天的尾巴(线段树合并)
题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地 ...
- koa学习笔记
卸载node http://www.it165.net/os/html/201504/12427.html 安装 sudo npm install -g n sudo n stable 装个稳定版试试 ...
- linux下的文本操作之 文本查找——grep
摘要:你有没有这样的应用场景:调试一个程序,出现debug的提示信息,现在你需要定位是哪个文件包含了这个debug信息,也就是说,你需要在一个目录下的多个文件(可能包含子目录)中查找某个字符串的位置: ...
- Kubernetes 自动伸缩 auto-scaling
使用 Kubernetes 的客户能够迅速响应终端用户的请求,交付软件也比以往更快.但是,当你的服务增长速度比预期更快时,计算资源不够时,该怎么处理呢? 此时可以很自豪地说: Kubernetes 1 ...
- java获取网络ip地址
在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实I ...
- byte[] 数组和字符串的转换,与byte[] 数组和int类型的之间的转化
我们先来看看byte bool int ushort 等的定义 首先时byte[]数组与string之间的转换 string 转换位byte[] 数组 string str = "1-1 ...
- 索引+sql优化
索引的概念: 索引是提高查询速度的一种手段.索引有很多种,以下是索引树的结构 要求查询出薪资大于5000的雇员信息,只要在树中找到5000的节点,直接查询该节点右边的数据即可,左边就不用管了,这样提高 ...
- ceph: health_warn clock skew detected on mon的解决办法
造成集群状态health_warn:clock skew detected on mon节点的原因有两个,一个是mon节点上ntp服务器未启动,另一个是ceph设置的mon的时间偏差阈值比较小. 排查 ...
- WORD wFormatTag; /* format type */ //设置波形声音的格式
0x0000 Microsoft Unknown Wave Format 0x0001 Microsoft PCM Format 0x0002 ...