intstr
这个包是偶然在k8s client-go中发现的, 在编写deployment
结构体定义时, apiv1.Container
实例下LivenessProbe
中用到的Port
, 就是intstr.IntOrString
. 特地看下来这个函数, 发现这个函数恰巧解决了一直困扰我的一个问题: 在restful
接口中, 如果要求json格式body
体内传递port
端口参数, 那么port
这个字段, 我应该在服务端定义成整型好呢, 还是字符串类型好呢, 一直很纠结~ 有了intstr.IntOrString
再也不用为这事儿发愁了
简介
以往我们接收json
或yaml
字符串要转成结构体时, 数据类型必须一一对应. 比如数据中的端口字段, 如果json
中传递是的整型, 则为以下样式 {"port": 8080}
; 如果传递的是字符串类型, 则为以下形式{"port": "8080"}
服务端接收到这些字符串后, 需要将数据与结构体中的字段一一绑定, 当然数据类型也必须一致. 如果在服务端定义了port
字段为int
, 但是json
字符串传递过来的是{"port": "8080"}
, 则绑定数据时将会报错. 反之也一样, 数据类型必须一致.
我自己开发过得项目中, 很多接口的body
体内都出现了端口字段, 有的时候定义为整型, 有的时候定义为字符串类型, api doc里也是有的写得整型, 有的写的字符串, 每次都纠结用什么类型好
intstr.IntOrString
数据类型顾名思义, 该类型可以既可以接受整型, 也可以接受字符串类型. 再也不用纠结这种用整型和字符串类型都合适的字段到底用什么数据类型了
intstr.IntOrString
不仅可以兼容接收整型或字符串类型, 而且可以通过其内置的函数, 在两个数据类型之间自由转换
json/yaml串转结构体
以下demo的场景为, 拿到json/yaml
串, 转换成结构体的使用场景
端口字段为整型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package main
import ( "encoding/json" "fmt" "k8s.io/apimachinery/pkg/util/intstr" )
type service struct { Name string `json:"name"` Host string `json:"host"` Port intstr.IntOrString `json:"port"` }
func main() {
jsonStr := `{"name": "nginx", "host": "192.168.1.2", "port": 8080}`
nginxService := &service{}
json.Unmarshal([]byte(jsonStr), nginxService)
fmt.Printf("提取数据类型: %T 实际数据类型(编号): %v 值: %#v \n", nginxService.Port.IntVal, nginxService.Port.Type, nginxService.Port.IntVal) fmt.Printf("提取数据类型: %T 实际数据类型(编号): %v 值: %#v \n", nginxService.Port.StrVal, nginxService.Port.Type, nginxService.Port.StrVal) }
|
运行结果:
1 2
| 提取数据类型: int32 实际数据类型(编号): 0 值: 8080 提取数据类型: string 实际数据类型(编号): 0 值: ""
|
上面的例子中, json字符串中的端口字段为整型, 绑定到结构体的实例后, 通过nginxService.Port.Type
可以取得json串中实际传递的是哪种数据类型, 在本例中, 调用nginxService.Port.Type
的结果是0
, 通过查看源码得知, 0
表示json串中传递的数据是整型
1 2 3 4 5 6 7 8
|
type Type int
const ( Int Type = iota String )
|
在实际使用时, 可以先判断nginxService.Port.Type
的结果是0, 还是1
- 如果是0, 则取整型
nginxService.Port.IntVal
- 如果是1, 则取字符串类型
nginxService.Port.StrVal
还有一种更直接的用法, 就是根据需要, 显式的类型转换
比如上面的例子中, json传递的端口值为整型, 但是服务端绑定到结构体之后, 当使用该端口时, 需要该端口值得数据类型为字符串类型, 你可以直接这样做:
fmt.Printf("%#v", nginxService.Port.String())
运行结果:
"8080"
可以看到, 整型的数据, 已经帮你转换成为字符串类型, 后期使用非常灵活, 可以随时提取两种数据类型的值
端口为字符串类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package main
import ( "encoding/json" "fmt" "k8s.io/apimachinery/pkg/util/intstr" )
type service struct { Name string `json:"name"` Host string `json:"host"` Port intstr.IntOrString `json:"port"` }
func main() {
jsonStr := `{"name": "nginx", "host": "192.168.1.2", "port": "8080""}` nginxService := &service{}
json.Unmarshal([]byte(jsonStr), nginxService)
fmt.Printf("提取数据类型: %T 实际数据类型(编号): %v 值: %#v \n", nginxService.Port.IntVal, nginxService.Port.Type, nginxService.Port.IntVal) fmt.Printf("提取数据类型: %T 实际数据类型(编号): %v 值: %#v \n", nginxService.Port.StrVal, nginxService.Port.Type, nginxService.Port.StrVal) fmt.Printf("值: %#v 实际数据类型: %T \t \n", nginxService.Port.String(), nginxService.Port.String()) fmt.Printf("值: %#v 实际数据类型: %T \t \n", nginxService.Port.String(), nginxService.Port.IntValue()) }
|
运行结果:
1 2 3 4
| 提取数据类型: int32 实际数据类型(编号): 1 值: 0 提取数据类型: string 实际数据类型(编号): 1 值: "8080" 值: "8080" 实际数据类型: string 值: "8080" 实际数据类型: int
|
结构体转json/yaml
数据类型: 整型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package main
import ( "encoding/json" "fmt" "k8s.io/apimachinery/pkg/util/intstr" )
type service struct { Name string `json:"name"` Host string `json:"host"` Port intstr.IntOrString `json:"port"` }
func main() { nginxService := service{ Name: "nginx", Host: "192.168.1.2", Port: intstr.IntOrString{ Type: 0, IntVal: 2222, StrVal: "1111", }, }
jsonBytes, _ := json.Marshal(nginxService) fmt.Println(string(jsonBytes)) }
|
注意上面intstr.IntOrString.Type
的值设置为0
, 运行结果:
1
| {"name":"nginx","host":"192.168.1.2","port":2222}
|
intstr.IntOrString.Type
的值设置为0
, 表示该结构体实例内的数据为整型, 故转json时, 按照IntVal
中的值来生成字符串
*注意: * 如果没有显式为intstr.IntOrString.Type
赋值, 则该值默认为0, 默认会取IntVal
中的数据, 也就是说, 可以简写为以下形式
1 2 3 4 5
| nginxService := service{ Name: "nginx", Host: "192.168.1.2", Port: intstr.IntOrString{IntVal: 2222}, }
|
数据类型: 字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package main
import ( "encoding/json" "fmt" "k8s.io/apimachinery/pkg/util/intstr" )
type service struct { Name string `json:"name"` Host string `json:"host"` Port intstr.IntOrString `json:"port"` }
func main() { nginxService := service{ Name: "nginx", Host: "192.168.1.2", Port: intstr.IntOrString{ Type: 1, IntVal: 2222, StrVal: "1111", }, }
jsonBytes, _ := json.Marshal(nginxService) fmt.Println(string(jsonBytes)) }
|
注意上面intstr.IntOrString.Type
的值设置为1
, 运行结果:
1
| {"name":"nginx","host":"192.168.1.2","port":"1111"}
|
intstr.IntOrString.Type
的值设置为1
, 表示该结构体实例内的数据为字符串类型, 故转json时, 按照StrVal
中的值来生成字符串