This is the 12th day of my participation in Gwen Challenge

In development, you’ll encounter converting a JSON string into a struct structure using reflection.

Go is a statically compiled class language. When we define variables, we already know what type they are. However, we sometimes encounter parameters of type interface{} in the process of using them. Then, any type of argument can be passed on a call, so inside a function you need to use reflection to know what type of argument is being passed.

func Println(a ...interface{})(n int,err error){
  return FPrintln(os.Stdout,a...)
}
Copy the code

Go language reflection definition, any interface consists of two parts: the specific type of the interface and the corresponding value of the specific type.

Interface{} is an empty Interface that can represent any type and convert any type to an empty Interface. It is commonly used for reflection, type assertion, to reduce repetitive code and simplify programming

  • Reflect. Value: The Value of the variable, obtained from reflect.ValueOf

  • Reflect. Type: The Type of the variable, obtained from reflect.typeof

func main(a){
  i := 2
  ival := reflect.valueOf(i)
  itype := reflect.TypeOf(i)
  fmt.Println(ival,itype)
}
Copy the code

reflect.Value

Reflect is a structure

type value struct{
	typ *type
	ptr unsafe.Pointer
	flag
}
Copy the code

Get the original type

An object of any type is converted to reflect.Value via reflect.valueOf. So reflect.Value goes back to the relative type object via the interface method.

func main(a){
	i := 3
	// int ==> reflect.Value
	iv := reflect.ValueOf(i)
	//reflect.value ==> int
  i1 := iv.interface(). (int)
  fmt.Println(i1)
}
Copy the code

Modify the corresponding value

Modify variables defined at run time through reflection

func main(a){
	i := 3
	ipv := reflect.ValueOf(&i)
  ipv.Elem().SetInt(4)
  fmt.Println(ipv)
}
Copy the code

The reflect.valueOf function takes a pointer, which finds the corresponding memory address, uses the Elem method to retrieve the pointed value, and then modifies its value.

If you change the value of a struct variable, if you change?

//1, pass the struct structure pointer, get the corresponding reflect.value
// the Elem method gets the value to which the pointer points
// the Field method gets the Field to be modified
// Set a series of methods to modify the corresponding value
func main(a){
  
type person struct {
		Name string  // Struct fields must be public, uppercase
		Age  int
	}
	stu := person{
		Name: "jasen",
		Age:  18,
	}

	stuRe := reflect.ValueOf(&stu)
	stuRe.Elem().Field(1).SetInt(20)

	fmt.Println("The revised age is.", stu.Age)
}
Copy the code

Note: If you want to change the value of a struct structure field, the field needs to be exportable, not private, i.e., the first letter of the field should be uppercase.

When I say that a field in the person structure is changed to lowercase, an error immediately occurs. You can try this:

panic: reflect: reflect.flag.mustBeAssignable using value obtained using unexported field
Copy the code

Getting the underlying type

In Go, we can declare many custom types through the keyword type, where the underlying type is the corresponding base type (interface, structure, pointer……).

p := person{name:"nanlv", age: 18}
pRef := reflect.ValueOf(&p)
fmt.Println(pRef.Kind())
pval := reflect.ValueOf(p)
fmt.Println(pval.Kind())

// Output the result
// pstr
// struct
Copy the code

The Kind method returns a value of Kind, which is a constant

reflect.Type

When our scenario needs to manipulate a variable’s type correlation, we can retrieve the variable’s type by using reflect.typeof

Reflect. Type is an interface

type Type interface {

    Implements(u Type) bool // Determine whether interface u is implemented
    AssignableTo(u Type) bool // can be assigned to the variable u, that is, can use =
   ConvertibleTo(u Type) bool // Can be converted to type u, that is, can be converted
    Comparable() bool // Is used to determine whether the type is comparable, that is, can be compared using relational operators
 
    // The following methods have the same function as the Value structure
   Kind() Kind

    Method(int) Method
   MethodByName(string) (Method, bool)
   NumMethod() int
   Elem() Type
   Field(i int) StructField
   FieldByIndex(index []int) StructField
   FieldByName(name string) (StructField, bool)
   FieldByNameFunc(match func(string) bool) (StructField, bool)
   NumField() int
 }
Copy the code

Iterate over structure fields and methods

p := person{name:"nanlv", age: 18}
pt := reflect.TypeOf(&p)

// Iterate over the Person field
for i :=0; i< pt.NumField(); i++ {
  fmt.Println("Field:",pt.Field(i).Name)
}
// Iterate through the person method
for i :=0; i< pt.NumMethod(); i++ {
  fmt.Println("Field:",pt.pt.Method(i).Name)
}
Copy the code
  • FieldByName gets the specified field
  • MethodByName Gets the specified method

JSON interturns with Struct

Go language standard library JSON package, can achieve this function

  • Json.Marshal function, struct to json
  • Json.Unmarshal, json to struct

Often when you define a structure, the field is public, the field name is uppercase, but our JSON string is lowercase, so we use struct tag

// Use struct tag
type person struct {
  Name string `json:"name"`  // `bson:"name"`
   Age int `json:"age"`
 }

// Use tag.get ("json") to Get the corresponding JSON field name
pt.Field(0).Tag.Get("json")
Copy the code

Get(“json”) to obtain the name of the corresponding JSON field

Struct Tags can be used as metadata configurations for structure fields in scenarios such as ORM mapping, XML transformation, generation of Swagger documents, and so on