当前位置:网站首页>Teach you how to use the reflect package to parse the structure of go - step 2: structure member traversal
Teach you how to use the reflect package to parse the structure of go - step 2: structure member traversal
2022-06-24 07:42:00 【amc】
Last article We learned how to use reflect Check the type of a parameter . This article , We get a structure type , Then we need to explore the internal structure of the structure and its corresponding values .
Structure member iteration
Last article , our marshal The function currently looks like this :
func marshalToValues(in interface{}) (kv url.Values, err error) {
v, err := validateMarshalParam(in)
if err != nil {
return nil, err
}
// ......
}Come here , We got one struct Of reflect.Value Variable . Next , Let's add a few more lines of code , It's like this :
func marshalToValues(in interface{}) (kv url.Values, err error) {
v, err := validateMarshalParam(in)
if err != nil {
return nil, err
}
t := v.Type()
numField := t.NumField()
kv = url.Values{}
// Iterate over each field
for i := 0; i < numField; i++ {
fv := v.Field(i) // field value
ft := t.Field(i) // field type
// ......
}
return kv, nil
} Variable t It's a reflect.Type, Indicates the type of the current variable , Its function NumField(), about struct Type variable , Indicates the number of all member fields under the variable .
Member resolution process
Iterate over each field in the structure , Then see fv := v.Field(i) and ft := t.Field(i). among fv A variable is reflect.Value type , After the last article , The reader is already familiar with . But variables tv It is reflect.StructField type , This is a new type . It represents the attributes of the field type in the structure .
For a structure member , In addition to the field body type , We will also check its other properties , It needs to use fv and ft Several parameters of variables , As shown below :
Anonymous members
Go In the structure of , Support anonymous members . Handling of anonymous members , There are several points to consider . Let's skip , It will be specifically explained later , So the code is as follows :
func marshalToValues(in interface{}) (kv url.Values, err error) {
// ......
// Iterate over each field
for i := 0; i < numField; i++ {
fv := v.Field(i) // field value
ft := t.Field(i) // field type
if ft.Anonymous { // Whether anonymous members
// TODO: We will deal with it later
continue
}
// ......
}
return kv, nil
}Members cannot be exported
Go In the structure of , share ( Exportable ) Members start with capital letters , And private ( Cannot export ) Members start with lowercase letters . according to Go The Convention of , It's going on marshal / unmarshal In operation , Private members are not handled , So these members , We should filter out non - processing .
But there is one exception : Anonymous members themselves may not be exportable , This needs to be handled differently . So we put the processing logic of anonymous members in front . So the code here is rewritten as follows :
func marshalToValues(in interface{}) (kv url.Values, err error) {
// ......
// Iterate over each field
for i := 0; i < numField; i++ {
fv := v.Field(i) // field value
ft := t.Field(i) // field type
if ft.Anonymous { // Whether anonymous members
// TODO: We will deal with it later
continue
}
if !fv.CanInterface() { // Can I export , Use fv Variable CanInterface Function to judge
continue
}
// ......
}
return kv, nil
}Go tag analysis
We know , stay Go Many of the marshal / unmarshal Function , For structure variables and byte streams key Mapping of values , Through the label in the structure , That is to say tag To achieve . For example, the following definition :
type Pet struct {
OwnerID string `url:"owner_id,omitempty" json:"ownerID"`
Name string `url:",omitempty"`
Sex int
} Through this tag, In the byte stream ownerID and OwnerID Variables are associated . hinder omitempty As tag Additional instructions for , Indicates when the field value is equal to the null value , The value of this field is not encoded .
as for Name Field , Because it is not clearly specified tag, Then the default setting is key Map to the same... As the variable name Name.
therefore , Since we write it ourselves marshal / unmarshal function , Obviously, it should also follow such a reference pattern . Let's write a short piece of code to parse this field tag Information , Participation is *reflect.StructField type , Implement the following functions :
- If specified tag Configuration is not empty , There are two cases : - Everything was good. There was content before , So the data before the comma is key name - There is nothing before the comma , In this case, the name of the field is used as tag
- If specified tag Configuration does not exist , The name of the field is used as tag
- Support to obtain other parameters
type tags []string
func readTag(ft *reflect.StructField, tag string) tags {
tg := ft.Tag.Get(tag)
// If tag Configuration is not empty , Then return to
if tg != "" {
res := strings.Split(tg, ",")
if res[0] != "" {
return res
}
return append(tags{ft.Name}, res[1:]...)
}
// If tag Configuration is empty , Then return the field name
return tags{ft.Name}
}
// Name At present tag The first field defined , This field must be a name
func (tg tags) Name() string {
return tg[0]
}
// Has Judge the present tag Whether some additional parameter values are configured , such as omitempty
func (tg tags) Has(opt string) bool {
for i := 1; i < len(tg); i++ {
t := tg[i]
if t == opt {
return true
}
}
return false
} Configuration above , It covers the new Pet Several of the types tag situation .
here , We just need to add another filter branch to continue down . This filter branch is : When tag The configuration value is equal to - when , according to Go The agreement of , This means that the change field is ignored :
func marshalToValues(in interface{}) (kv url.Values, err error) {
// ......
// Iterate over each field
for i := 0; i < numField; i++ {
fv := v.Field(i) // field value
ft := t.Field(i) // field type
if ft.Anonymous { // Whether anonymous members
// TODO: We will deal with it later
continue
}
if !fv.CanInterface() { // Can I export , Use fv Variable CanInterface Function to judge
continue
}
tg := readTag(&ft, "url")
if tg.Name() == "-" { // - Indicates that the current field is ignored
continue
}
// ......
}
return kv, nil
}Structure member value reading
After the previous filtration , We are here , You can already get everything you need to deal with 、 Legal structure field information , The next step is to get the value of each structure member .
This step we use fv Variable , This is a reflect.Value type . For different data types , Different methods of taking values .
Here, please review reflect.Kind type , At this stage , For the time being, let's deal with the following data types :
- character string
- integer
- floating-point
- Boolean type
Other types are more complex , We will explain further later .
It's no use saying more , This short piece of code is not long , As shown below :
func readFieldVal(v *reflect.Value, tag tags) (s string, ok bool) {
switch v.Type().Kind() {
default:
return "", false // Unsupported variable type , Go straight back to
case reflect.String:
return v.String(), true
case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
return strconv.FormatInt(v.Int(), 10), true
case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
return strconv.FormatUint(v.Uint(), 10), true
case reflect.Bool:
return fmt.Sprintf("%v", v.Bool()), true
case reflect.Float64, reflect.Float32:
return strconv.FormatFloat(v.Float(), 'f', -1, 64), true
}
}The code shows various types of value taking functions :
type | Value function | remarks |
|---|---|---|
character string |
| |
Unsigned integer |
| No matter how wide the seat is , Unified access |
signed int |
| No matter how wide the seat is , Unified access |
|
| |
Floating point numbers |
| Unified access |
therefore , Soon! , The body of our iterated function , It's done. :
func marshalToValues(in interface{}) (kv url.Values, err error) {
v, err := validateMarshalParam(in)
if err != nil {
return nil, err
}
t := v.Type()
numField := t.NumField() // The number of all fields under the structure
kv = url.Values{}
// Iterate over each field
for i := 0; i < numField; i++ {
fv := v.Field(i) // field value
ft := t.Field(i) // field type
if ft.Anonymous {
// TODO: We will deal with it later
continue
}
if !fv.CanInterface() {
continue
}
tg := readTag(&ft, "url")
if tg.Name() == "-" {
continue
}
str, ok := readFieldVal(&fv, tg)
if !ok {
continue
}
if str == "" && tg.Has("omitempty") {
continue
}
// Write KV value
kv.Set(tg.Name(), str)
}
return kv, nil
}verification
Let's write a simple one Go test Function to verify :
func TestMarshal(t *testing.T) {
type Pet struct {
OwnerID string `url:"owner_id,omitempty" json:"ownerID"`
Name string `url:",omitempty"`
Sex int
}
p := Pet{
OwnerID: "tencent",
Name: "Penguin",
Sex: 1,
}
s, _ := Marshal(&p)
t.Log(string(s))
}
// Output
// Name=Penguin&Sex=1&owner_id=tencentYou can see , In the output content, correctly follow tag Configuration in , Serialize the fields in the structure into a byte stream .
next step
OK, If the reader's needs , Just serialize the basic data types ( character string 、 Boolean value 、 Numbers ), So far ,marshal Function can be regarded as completed .
But do readers remember what we left in this article TODO term , This is what we need to deal with in the next article . The code of this article can also be found in Github Found on the , The codes in this phase correspond to Commit b2db350.
Other articles recommend
- It's still in use map[string]interface{} Handle JSON? Tell you a more efficient way ——jsonvalue
- Go Language native json What's wrong with the bag ? How to better handle JSON data ?
- I'll teach you how to use reflect Package parsing Go The structure of the body - Step 1: Parameter type check
- I'll teach you how to use reflect Package parsing Go The structure of the body - Step 3: Complex type checking
This article adopts Creative Commons signature - Noncommercial use - Share in the same way 4.0 International licensing agreement Licensing .
The original author : amc, Welcome to reprint , But please note the source .
Original title :《 I'll teach you how to use reflect Package parsing Go The structure of the body - Step 2: Structure member traversal 》
Release date :2021-06-29
Link to the original text :https://cloud.tencent.com/developer/article/1839920.
边栏推荐
- Dichotomous special training
- 图形技术之坐标转换
- [image fusion] image fusion based on directional discrete cosine transform and principal component analysis with matlab code
- Ultra wideband pulse positioning scheme, UWB precise positioning technology, wireless indoor positioning application
- Accessing user interface settings using systemparametersinfo
- UTC、GMT、CST
- Knowledge points of 2022 system integration project management engineer examination: ITSS information technology service
- Wechat cloud hosting hot issues Q & A
- Reconfiguration of nebula integration testing framework based on BDD theory (Part 2)
- What should I pay attention to after the live broadcast system source code is set up?
猜你喜欢

Win11 points how to divide disks? How to divide disks in win11 system?

LeetCode 207:课程表(拓扑排序判断是否成环)
![[pointnet] matlab simulation of 3D point cloud target classification and recognition based on pointnet](/img/86/5db689cdac2a927a23dff3fb9594b0.png)
[pointnet] matlab simulation of 3D point cloud target classification and recognition based on pointnet

Maxcompute remote connection, uploading and downloading data files

bjdctf_ 2020_ babystack

Buuctf misc grab from the doll
![[vulhub shooting range]] ZABBIX SQL injection (cve-2016-10134) vulnerability recurrence](/img/c5/f548223666d7379a7d4aaed2953587.png)
[vulhub shooting range]] ZABBIX SQL injection (cve-2016-10134) vulnerability recurrence

使用SystemParametersInfo访问用户界面设置

6000多万铲屎官,捧得出一个国产主粮的春天吗?

只显示两行,超出部分省略号显示
随机推荐
[frame rate doubling] development and implementation of FPGA based video frame rate doubling system Verilog
Knowledge points of 2022 system integration project management engineer examination: ITSS information technology service
Spark stage and shuffle for daily data processing
什么是CC攻击?如何判断网站是否被CC攻击? CC攻击怎么防御?
向量操作与坐标转换相关方法
New features of PHP: bytecode cache and built-in server
与(&&)逻辑或(||),动态绑定结合三目运算
图形技术之管线概念
MaxCompute远程连接,上传、下载数据文件操作
Reconfiguration of nebula integration testing framework based on BDD theory (Part 2)
LeetCode 207:课程表(拓扑排序判断是否成环)
atguigu----16-自定义指令
使用SystemParametersInfo访问用户界面设置
[OGeek2019]babyrop
《canvas》之第3章 曲线图形
tuple(元组)备注
位运算
相机标定(标定目的、原理)
What should I pay attention to after the live broadcast system source code is set up?
洛谷 P1051 谁拿了最多奖学金