Go Series Tutorial--34. Reflection

Source: Internet
Author: User
! [Reflection] (https://raw.githubusercontent.com/studygolang/gctt-images/master/golang-series/reflection-golang-3.png) Welcome to [ Golang Series Tutorial] (HTTPS://STUDYGOLANG.COM/SUBJECT/2) the 34th chapter. Reflection is one of the advanced topics in the Go language. I'll try to make it easy to understand. This tutorial is divided into the following subsections. -What is reflection? -Why do I need to check the variables to determine the types of variables? -Reflect bag-reflect. Type and reflect. Value-reflect. Kind-numfield () and Field () methods-Int () and String () method-complete program-Should we use reflection? Let's discuss each of these chapters individually. # # What is reflection? Reflection is the ability of a program to check variables and values at run time to find out their type. You may not understand, it's okay. At the end of this tutorial, you will have a clear understanding of reflection, so follow our tutorials to learn. # # Why do I need to check variables to determine the type of variables? When learning to reflect, everyone's first question is: if every variable in the program is defined by ourselves, then at compile time we can know the variable type, why do we need to check the variable at run time, find out its type? Yes, that's true for most of the time, but not always. Let me explain it to you. Let's write a simple program. "' Gopackage mainimport (" FMT ") func main () {i: = ten fmt. Printf ("%d%T", I, I)} ' [Run on Playground] (https://play.golang.org/p/1oZzPCCG2Qw) in the above program, the ' I ' type is known at compile time, Then we print out the ' I ' on the next line. There's nothing special about this place. Now, let's look at the case where the variable type needs to be evaluated at run time. If we were to write a simple function, it would receive the struct as an argument and use it to create a SQL insert query. Consider the following program: "' Gopackage mainimport (" FMT ") type order struct {Ordid int customerId int}func main () {o: = order{ordid:1234 , Customerid:567,} fmt. Println (o)} ' [Run on Playground] (https://play.golang.org/p/1oZzPCCG2Qw) in the above program, we need to write a function that receives the struct variable ' o ' as a parameter and returns the following SQL Insert Query. ' INSERT into order values (1234, 567) ' This function is simple to write. Let's write this function now. ' Gopackage mainimport ("FMT") type order struct {ordid int customerId int}func createquery (o Order) string {i: = Fmt.s printf ("INSERT into order values (%d,%d)", O.ordid, O.customerid) return I}func main () {o: = order{ordid:1234, customer id:567,} fmt. Println (CreateQuery (o))} "[Run on Playground] (https://play.golang.org/p/jhz4VHKIlQ5) on line 12th, ' createquery ' function with ' o ' Two fields (' Ordid ' and ' customerId '), creating an Insert query. The program will output: ' ' Bashinsert into order values (1234, 567) ' Now let's upgrade this query builder. What if we want to make it generic and apply to any type of struct? We use the procedure to understand. "' Gopackage maintype order struct {ordid int customerId int}type employee struct {name string id int address string sal ary int Country String}func createquery (q interface{}) string {}func main () {} "" Our goal is to complete the ' createquery ' function (line 16th in the above program), It can receive any struct as an argument, creating an Insert query based on the field of the struct. For example, if wePass in the following struct: "' goo: = order {ordid:1234, customerid:567} ' createquery ' function should return: ' ' INSERT into order values (1234, 567) ' Similarly, if we pass in: "Go e: = employee {name:" Naveen ", id:565, Address:" Science Park Road, Singapore ", salary:90000, Country: "Singapore",} ' "' This function will return: ' ' INSERT into employee values (" Naveen ", 565," Science Park Road, Singapore ", 90000," Singapore ") ' Because the ' createquery ' function should apply to any struct, it receives ' interface{} ' as a parameter. For simplicity, we only work with structs that contain the ' string ' and ' int ' type fields, but can be extended to include any type of field. The ' createquery ' function should be applied to all structures. Therefore, to write this function, you must check the type of the passed struct parameter at run time, locate the struct field, and then create the query. Then we need to use reflection. In the next step of this tutorial, we will learn how to implement it using the ' reflect ' package. # # Reflect package in the Go language, [' Reflect '] (https://golang.org/pkg/reflect/) implements run-time reflection. The ' reflect ' package will help identify the underlying concrete type and the specific value of the [' interface{} '] (https://studygolang.com/articles/12266) variable. That's exactly what we need. The ' createquery ' function receives the ' interface{} ' parameter, creating a SQL query based on its specific type and specific values. This is where the ' reflect ' package can help us. Before writing our generic query Builder, we first need to understand the several types and methods in the ' reflect ' package. Let's take a look at each one individually. # # # reflect. Type and reflect. Value ' reflect. Type ' represents ' interface{} ' of the specific type, while ' reflect '. ValUE ' indicates its specific value. ' Reflect. TypeOf () ' and ' reflect. ValueOf () ' Two functions can return ' reflect ' respectively. Type ' and ' reflect. Value '. These two types are the basis for us to create the Query builder. We now use a simple example to understand these two types. "' Gopackage mainimport (" FMT "" reflect ") type order struct {ordid int customerId int}func createquery (q interface{}) {T : = Reflect. TypeOf (q) V: = reflect. ValueOf (q) fmt. Println ("Type", T) fmt. Println ("Value", V)}func main () {o: = order{ordid:456, customerid:56,} createquery (O)} ' [Run on playground] (https:// PLAY.GOLANG.ORG/P/81BS-BEFBCG) in the above program, the ' createquery ' function in line 13th receives ' interface{} ' as a parameter. In line 14th, [' reflect. TypeOf '] (https://golang.org/pkg/reflect/#TypeOf) received the parameter ' interface{} ' and returned [' reflect. Type '] (https://golang.org/pkg/reflect/#Type), which contains the specific type of the passed ' interface{} ' argument. Similarly, on line 15th, [' reflect. The ValueOf '] (https://golang.org/pkg/reflect/#ValueOf) function receives the parameter ' interface{} ' and returns the [' reflect. Value '] (https://golang.org/pkg/reflect/#Value), which contains the specific value of the ' interface{} '. The above program will print: ' ' type Main.ordervalue {456 56} ' from the output we can see that the program prints the specific type and the specific value of the interface. # # # Relfect. The Kind ' reflect ' package also has a heavyType: [' Kind '] (https://golang.org/pkg/reflect/#Kind). The types of ' Kind ' and ' type ' may look similar in reflection packages, but they can be clearly seen in the following procedures. "' Gopackage mainimport (" FMT "" reflect ") type order struct {ordid int customerId int}func createquery (q interface{}) {T : = Reflect. TypeOf (q) k: = T.kind () fmt. Println ("Type", T) fmt. Println ("Kind", K)}func main () {o: = order{ordid:456, customerid:56,} createquery (O)} ' [Run on playground] (https://p LAY.GOLANG.ORG/P/XW3JIZCM54T) The above program will output: "' Type main.orderkind struct '" I think you should know the difference. ' type ' represents the actual type of ' interface{} ' (Here is * * ' main. Order ' * *), while ' Kind ' denotes a specific category of that type (here is * * ' struct ' * *). # # # Numfield () and the field () method [' Numfield () '] (https://golang.org/pkg/reflect/#Value. Numfield) method returns the number of fields in the struct, while the [' Field (i int) '] (https://golang.org/pkg/reflect/#Value. Field) method returns the ' reflect ' of the field ' I '. Value '. "' Gopackage mainimport (" FMT "" reflect ") type order struct {ordid int customerId int}func createquery (q interface{}) {I F reflect. ValueOf (q). Kind () = = reflect. Struct {V: = reflect. ValueOf (q) fmt. Println ("NuMber of Fields ", V.numfield ()) for I: = 0; I < V.numfield (); i++ {fmt. Printf ("field:%d type:%t value:%v\n", I, V.field (i), V.field (i))}}}func main () {o: = order{ordid:456, customerid:56, } createquery (O)} "[Run on Playground] (https://play.golang.org/p/FBHfJfuTaEe) in the program above, because the ' Numfield ' method can only be used on the struct, we Line 14 first checks that the category ' Q ' is ' struct '. Other code of the program is easy to read and does not explain. The program will output: ' ' Number of fields 2field:0 type:reflect. Value value:456field:1 Type:reflect. Value value:56 ' # # # int () and string () method [' Int '] (https://golang.org/pkg/reflect/#Value. int) and [' String '] (https:// golang.org/pkg/reflect/#Value. String) helps us to remove ' reflect ' separately. Value ' as ' Int64 ' and ' string '. "' Gopackage mainimport (" FMT "" reflect ") func main () {A: = x: = reflect. ValueOf (a). Int () fmt. Printf ("Type:%t value:%v\n", x, x) b: = "Naveen" y: = reflect. ValueOf (b). String () fmt. Printf ("Type:%t value:%v\n", Y, Y)} "[Run on Playground] (Https://play.golang.org/p/UIllrLVoGwI) in the above program in line 10th, we take out ' Reflect. Value ', and converted to ' Int64 ', while in line 13th we take out ' reflect '. Value 'and convert it to ' string '. The program will output: ' ' Type:int64 value:56type:string value:naveen ' # # Full program Now that we have enough knowledge to complete our query generator, let's implement it. "' Gopackage mainimport (" FMT "" reflect ") type order struct {ordid int customerId int}type employee struct {name string ID int address string salary int country String}func createquery (q interface{}) {if reflect. ValueOf (q). Kind () = = reflect. Struct {t: = reflect. TypeOf (q). Name () Query: = FMT. Sprintf ("INSERT into%s values (", t) V: = reflect. ValueOf (q) for I: = 0; I < V.numfield (); i++ {switch V.field (i). Kind () {case reflect. Int:if i = = 0 {query = FMT. Sprintf ("%s%d", Query, V.field (i). Int ())} else {query = FMT. Sprintf ("%s,%d", query, V.field (i).) Int ())} case reflect. String:if i = = 0 {query = FMT. Sprintf ("%s\"%s\ "", Query, V.field (i). String ())} else {query = FMT. Sprintf ("%s, \"%s\ "", Query, V.field (i). String ())} default:fmt. PRINTLN ("Unsupported type") return}} query = Fmt. Sprintf ("%s)", query) FMT. Println (query) return} FMT. PRINTLN ("Unsupported type")}Func main () {o: = order{ordid:456, customerid:56,} createquery (o) E: = employee{name: "Naveen", id:565, Address: "C Oimbatore ", salary:90000, Country:" India ",} createquery (e) I: = CreateQuery (i)}" [Run on playground] (https://play.go lang.org/p/82bi4ru5c7w) In line 22nd, we first check to see if the argument is a struct. In line 23rd, we use the ' Name () ' method, from the ' reflect ' of the struct body. Type ' Gets the name of the struct. In the next line, we use ' t ' to create the query. In line 28th, [Case statement] (https://studygolang.com/articles/11957) checks whether the current field is ' reflect '. int ', if so, we take the value of the field and use the ' Int () ' method to convert to ' int64 '. [If Else statement] (https://studygolang.com/articles/11902) is used to handle boundary conditions. Please add a log to understand why it is needed. In line 34th, we use the same logic to fetch ' string '. We also made additional checks to prevent the ' createquery ' function from crashing when it passed into an unsupported type. The other code of the program is self explanatory. I suggest you add logs in the right place, check the output to get a better understanding of the program. The program outputs: "INSERT into order values (456, a) INSERT into employee values (" Naveen ", 565," Coimbatore ", 90000," India ") Unsupp orted type "To add a field name to the output query, we leave it to the reader as an exercise. Please try to modify the program to print out the query in the following format. ' INSERT into order (Ordid, CustomerId) VALUES (456, 56) ' # # Should we use reflection? We have shown the actual application of reflection and now consider a very realistic question. Should we use reflection? I'd like to quote [' Rob Pike '] (https://en.wikipedia.org/wiki/Rob_Pike) To answer this question about the use of reflection's motto. > clarity is better than cleverness. And reflection is not at a glance. Reflection is a very powerful and advanced concept in the Go language, and we should use it with caution. It is very difficult to write clear and maintainable code using reflection. You should avoid using it whenever possible, and use reflection only when you must use it. This concludes the tutorial. I hope you like it. Have a nice day. * * Previous Tutorial-[function is first class citizen] (https://studygolang.com/articles/12789) * * * * * * Previous tutorial-[Read file] (https://studygolang.com/articles/14669 )**

via:https://golangbot.com/reflection/

Author: Nick Coghlan Translator: Noluye proofreading: polaris1119

This article by GCTT original compilation, go language Chinese network honor launches

This article was originally translated by GCTT and the Go Language Chinese network. Also want to join the ranks of translators, for open source to do some of their own contribution? Welcome to join Gctt!
Translation work and translations are published only for the purpose of learning and communication, translation work in accordance with the provisions of the CC-BY-NC-SA agreement, if our work has violated your interests, please contact us promptly.
Welcome to the CC-BY-NC-SA agreement, please mark and keep the original/translation link and author/translator information in the text.
The article only represents the author's knowledge and views, if there are different points of view, please line up downstairs to spit groove

2,114 Reads

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.