This is a creation in Article, where the information may have evolved or changed.
What's wasting today is tomorrow to those who died yesterday; What's the future of hate now?
What you are wasting today is the tomorrow that the man who died yesterday expects, and what you dislike is now the future you will never go back to.
Go is a statically typed language. Each variable has a static type, which means that the type of each variable is determined at compile time: Int,float32, *autotype, []byte, Chan []int and so on.
Type of movement
At compile time it is known that the variable type is static type, and the runtime knows that a variable type is called a dynamic type.
1. Static type
A static type is the type given when a variable is declared. Like what:
type MyInt int // int 就是静态类型type A struct{ Name string // string就是静态}var i *int // *int就是静态类型
2. Dynamic type
Dynamic type: The type of this value when the runtime copies it to this variable (no dynamic type if the value is nil). The dynamic type of a variable may change at run time, which depends primarily on its assignment (provided that the variable is the interface type).
var A interface{} // 静态类型interface{}A = 10 // 静态类型为interface{} 动态为intA = "String" // 静态类型为interface{} 动态为stringvar M *intA = M // 猜猜这个呢?
Take a look at this example:
//定义一个接口type Abc interface{String() string}// 类型type Efg struct{data string}// 类型Efg实现Abc接口func (e *Efg)String()string{return e.data}// 获取一个*Efg实例func GetEfg() *Efg{return nil}// 比较func CheckAE(a Abc) bool{return a == nil}func main() {efg := GetEfg()b := CheckAE(efg)fmt.Println(b)os.Exit(1)}
About dynamic static type on to here, the details please Google, Baidu Bar.
Reflection
So when do you use reflection?
Sometimes you want to use variables at run time to handle variables that use information that does not exist when you write your program. Perhaps you are trying to map data from a file or network request to a variable. Perhaps create a tool that works for different types. In these cases, you need to use reflection. reflection enables you to check the type at run time. It also allows you to check, modify, and create variables, functions, and structures at run time.
Type
You can use reflection to get the type of the variable: var t: = reflect. Typeof (v). The return value is a reflect. Type. There are many well-defined ways to use this value.
Name ()
Returns the name of the type. However, like a slice or pointer without a type name, only an empty string can be returned.
Kind ()
Kind is composed of slice, map, pointer pointer, struct, interface, string, Array, Function, int, or other basic type. Make a distinction before kind and type. If you define a type foo struct {}, then kind is the struct and type is foo.
* Small Knowledge point : The return value of the kind method corresponding to the reflection variable is a base type, not a static type. In the following example:
type MyInt intvar x MyInt = 7v := reflect.ValueOf(x)
The kind of the variable v is still reflect. Int, not myint this static type. The type can represent static types, and kind cannot.
* Note : When using the REFELCT package, the reflect package assumes you already know what you are doing, otherwise it throws panic. For example you have called with the current reflect. Type on different types of methods, then the panic is raised.
Elem ()
If your variable is a pointer, map, slice, channel, Array. Then you can use reflect. Typeof (v). Elem () to determine the type of containment.
Case code
Type Foo struct {A int ' tag1: "Tag1" Tag2: "Second Tag" ' B string}func Main () {//STRUCTF: = Foo{a:10, B: "Salutations"}//St Ruct type of pointer fptr: = &f//MAPM: = map[string]int{"A": 1, "B": 2}//Channelch: = make (chan int)//slicesl:= []int{1,32,34}/ /stringstr: = "string var"//String pointer strptr: = &STRTMAP: = Examiner (reflect. TypeOf (f), 0) Tmapptr: = Examiner (reflect. TypeOf (Fptr), 0) TMAPM: = Examiner (reflect. TypeOf (M), 0) TMAPCH: = Examiner (reflect. TYPEOF (CH), 0) TMAPSL: = Examiner (reflect. TYPEOF (SL), 0) Tmapstr: = Examiner (reflect. TypeOf (str), 0) Tmapstrptr: = Examiner (reflect. TypeOf (STRPTR), 0) fmt. Println ("TMap:", TMap) fmt. Println ("Tmapptr:", Tmapptr) fmt. Println ("TMAPM:", TMAPM) fmt. Println ("tmapch:", tmapch) fmt. Println ("TMAPSL:", TMAPSL) fmt. Println ("Tmapstr:", Tmapstr) fmt. Println ("Tmapstrptr:", tmapstrptr)}//type and the type of the element is judged by the Func Examiner (t reflect. Type, depth int) Map[int]map[string]string{outtype: = Make (map[int]map[string]string)//If it is a type, re-verify switch T.kind () { Case reflect. Array, reflect. Chan, reflect. Map, reflect. PTR, reflect. Slice:fmt. Println ("These types of Name are empty strings:", T.name (), ", Kind Yes:", T.kind ())///recursive query element type TMAP: = Examiner (T.elem (), depth) for k, V: = Range TMa P{outtype[k] = v}case reflect. Struct:for I: = 0; I < T.numfield (); i++ {f: = T.field (i)//reflect field outtype[i] = map[string]string{"Name": F.name, "Kind": f.type.string (),}}default:// Direct authentication Type Outtype = Map[int] map[string]string{depth:{"Name": T.name (), "Kind": T.kind (). String ()}}}return Outtype}
Operation Result:
where T. Field (index) must be used on a struct, so a document can be read carefully
Use reflection to read, set, create
After reading the above about the reflect detection variable type, we use reflection to read, set, and create.
To read the value of a variable, you first need a reflect. Valueof (Var) instance (Reflectval: = reflect. Valueof (Var), you can also get the type of the variable.
To modify the value of a variable, a reference to the pointer must be canceled by the pointer address of the variable. by refptrval: = reflect. Valueof ( &var ) way to get pointer type, you use Refptrval.elem (). Set (a new reflect. Value) to make changes, the values passed to set () must also be a reflect.value.
To create a value, use newptrval: = reflect. New (VarType) passes a reflect. Type. The returned pointer type can be written to the value using the modified method above.
Finally, you can return a normal variable by calling the interface () method. Because Golang does not have a generic type, the original type of the variable is lost; The method returns a value of type interface{}. If you create a pointer so that you can modify the value, you need to use Elem (). Interface () to dereference the reflect pointer. In both cases, you need to convert the empty interface to the actual type in order to use it.
Instance code:
type Foo struct {A int `tag1:"Tag1" tag2:"Second Tag"`B string}func main(){// 反射的使用s := "String字符串"fo := Foo{A: 10, B: "字段String字符串"}sVal := reflect.ValueOf(s)// 在没有获取指针的前提下,我们只能读取变量的值。fmt.Println(sVal.Interface())sPtr := reflect.ValueOf(&s)sPtr.Elem().Set(reflect.ValueOf("修改值1"))sPtr.Elem().SetString("修改值2")// 修改指针指向的值,原变量改变fmt.Println(s)fmt.Println(sPtr) // 要注意这是一个指针变量,其值是一个指针地址foType := reflect.TypeOf(fo)foVal := reflect.New(foType)// foVal.Elem().Field(0).SetString("A") // 引发panicfoVal.Elem().Field(0).SetInt(1)foVal.Elem().Field(1).SetString("B")f2 := foVal.Elem().Interface().(Foo)fmt.Printf("%+v, %d, %s\n", f2, f2.A, f2.B)}
Operation Result:
Memory for 10 seconds.
Create slice, map, chan
In addition to creating instances of built-in and user-defined types, you can use reflection to create instances that typically require the make feature. Use reflect. Makeslice,reflect. Makemap and Reflect.makechan functions to make slice,map or channel.
// 反射创建map slice channelintSlice := make([]int, 0)mapStringInt := make(map[string]int)sliceType := reflect.TypeOf(intSlice)mapType := reflect.TypeOf(mapStringInt)// 创建新值intSliceReflect := reflect.MakeSlice(sliceType, 0, 0)mapReflect := reflect.MakeMap(mapType)// 使用新创建的变量v := 10rv := reflect.ValueOf(v)intSliceReflect = reflect.Append(intSliceReflect, rv)intSlice2 := intSliceReflect.Interface().([]int)fmt.Println(intSlice2)k := "hello"rk := reflect.ValueOf(k)mapReflect.SetMapIndex(rk, rv)mapStringInt2 := mapReflect.Interface().(map[string]int)fmt.Println(mapStringInt2)
Operation Result:
Create a function
Use reflect. Makefunc () created, this function needs the reflect.type of the function we want to do and an input parameter is [] reflect.value type slice, and its output parameter is also the type [] reflect.value of the closure. The following is a simple example that detects the execution duration of any given function:
Package Mainimport ("reflect" "Time" "FMT" "Runtime")/* will create a Func wrapper, non-reflect. The Func type will panic of course Makefunc's closure function expression type is fixed, so you can look up the document. Read the reflect of the document carefully. Value.call () method. */func maketimedfunction (f interface{}) interface{} {rf: = reflect. TypeOf (f) if RF. Kind ()! = reflect. Func {Panic ("non-Reflect.func")}VF: = reflect. ValueOf (f) Wrapperf: = reflect. Makefunc (RF, func (in []reflect. Value) []reflect. Value {start: = time. Now () Out: = VF. Call (in) End: = time. Now () Fmt. PRINTF ("Calling%s took%v\n", runtime. FUNCFORPC (VF. Pointer ()). Name (), end. Sub (start)) return out}) return Wrapperf.interface ()}func time1 () {fmt. Println ("time1func===starting") time. Sleep (1 * time. Second) fmt. Println ("time1func===ending")}func time2 (a int) int {fmt. Println ("time2func===starting") time. Sleep (time. Duration (a) * time. Second) Result: = A * 2fmt. Println ("time2func===ending") return Result}func main () {timed: = Maketimedfunction (time1). ( Func ()) timed () Timedtoo: = Maketimedfunction (time2). (func (int) int) Time2val: = Timedtoo (5) fmt. Println (Time2val)}
Operation Result:
Analysis:
Reflect. The Value.call (Var) document is as follows:
Extended Call ()
The first thing we can confirm is that the function is like a normal variable, and if Foo () is a function, then f: = Foo is also set up.
The types of functions and methods in reflection are reflect. Func, if you want to invoke a function, you can pass the call () method of Value, for example:
func Halou(){fmt.Println("This is Halou函数! 6666")}func main(){// Call()扩展h := HalouhVal := reflect.ValueOf(h)fmt.Println("hVal is reflect.Func ?", hVal.Kind() == reflect.Func)hVal.Call(nil)}
Operation Result:
Reflect. The parameter of the call () method of Value is a reflect. The slice of value, corresponding to the parameter of the reflected function type, is also a reflect of the return value. The slice of value also corresponds to the return value of the reflected function type. So:
func Halou2(s string)string{return "接受到参数:"+s+", 但这是返回值!"}func main(){h2 := reflect.ValueOf(Halou2)params := []reflect.Value{reflect.ValueOf("参数1"),}h2ReturnVal := h2.Call(params)fmt.Println(h2ReturnVal)}
Leave a question!
The ability to function independently of any individual survives, but the method relies on the existence of the object. The method is an "object" behavior. So how do you invoke the method through reflection?