Golang automatic binding of struct and params using reflect package

Source: Internet
Author: User
Tags email string
This is a creation in Article, where the information may have evolved or changed.

Objective

Because the Golang static strongly typed language feature and the lack of good generic support lead to writing Web services with go, it always takes a lot of time to parse and type-convert the HTTP params, and it makes the code redundant, so what can I do to solve this pain? The answer is yes, I'll tell you how to use the reflect package to write a tool class to implement the auto-map binding between the model layer struct and the HTTP params.

The implementation is very simple, the main use is to get the reflect.TypeOf() type of the field (including the field name, type, tag description and other related information), as well as reflect.ValueOf() to get the field value type used to replicate the data obtained from the params, but also pay attention to the different types of values at the Set time of the difference.

Materials

First we design a struct to store the properties of each reflection field, such as the following.
Note: Depending on the Golang's implementation of the reflection model, this operation is not so efficient in go, it is recommended to cache a result to memory after the first reflection, so that it can be acquired directly at the next use.

type field struct {name     stringdef      booldefValue reflect.Valuerequired bool}

Through range reflect. The Type gets the struct field information and populates []*field it, including whether the field must be passed, the default value, or the field name, which can be implemented using the custom TAG description.

type Account struct {Email string `params:"email;required"`Name  string `params:"name;required"`Sign  string `params:"sign"`San   int    `params:"sam" defalut:"-99999"`}

Besides, we're going to need a bitmap. Used to map reflect.Kind the corresponding type relationship so that the type conversion is done at Set Value

var bitMap = map[reflect.Kind]int{reflect.Int.Stringreflect.Int:     32,reflect.Int16:   16,reflect.Int32:   32,reflect.Int64:   64,reflect.Int8:    8,reflect.Uint:    32,reflect.Uint16:  16,reflect.Uint32:  32,reflect.Uint64:  64,reflect.Uint8:   8,reflect.Float32: 32,reflect.Float64: 64,}

Realize

When we complete the above materials, want to realize our function that is easy, just need us to range define a good field slice, in turn from the value in the url.Values Get parameter, because the HTTP protocol request message is text-oriented no additional type description, So the data we get are all text types, and we need to reflect.Kind invoke different methods based on different types Set .

func setValue(data string, v reflect.Value) (err error) {kind := v.Kind()switch kind {case reflect.Int64, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int:var d int64d, err = strconv.ParseInt(data, 10, bitMap[kind])if err != nil {return}v.SetInt(d)case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint8:var d uint64d, err = strconv.ParseUint(data, 10, bitMap[kind])if err != nil {return}v.SetUint(d)case reflect.Float64, reflect.Float32:var d float64d, err = strconv.ParseFloat(data, bitMap[kind])if err != nil {return}v.SetFloat(d)case reflect.String:if data == "" {return}v.SetString(data)return

Reflect performance optimization

Reflect slow mainly has two reasons: one is related to memory allocation malloc after the GC (which improved in Go 1.9 vsersion), and the other is that the reflect implementation has a large number of enumerations, as well as type deduction, and the reflect.ValueOf() resulting reflect.Value type is a The value of the body, each reflection needs to be re- malloc added, which slows down the whole process.

So what if we don't use the reflect.ValueOf() data that gets the value and use reflect.TypeOf() the result directly struct , would it be faster to dispense with a layer of reflection? The answer, of course, is certain! directly on the code ~

func setValueWithPointer() {acc := &Account{}tp := reflect.TypeOf(acc).Elem()field, _ := tp.FieldByName("Email")fieldPtr := uintptr(unsafe.Pointer(acc)) + field.Offset*((*string)(unsafe.Pointer(fieldPtr))) = "admin#otokaze.cn"fmt.Println(acc) // stdout: &{admin#otokaze.cn   0}}

We have cleverly used the offset of the reflect.TypeOf() internal field memory address reserved for our struct, and also because uintptr() the strong turn is a shape memory address, which can be arithmetic operations, as long as the initialization of the struct after the allocation of the memory address of the beginning of the Storage plus field memory The offset of the address, we can directly get the field in the physical memory address, so as to write what we need. The most straightforward way to do this is to save reflect.ValueOf() two of reflections, and also to achieve our purpose of modification.

Above, so long as mastered the correct posture, Golang the reflection efficiency can still have a great increase! Reflective scenarios are far more than that, we all know that because static language relationships in Golang do not have the same support as mutable variables in PHP, they $$ can also be reflected to achieve similar effects, but this is not the scope of this article today, it as a knowledge point, and guidance. There are more tricks waiting for you to find out ~

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.