Preface:
I often hear some frequently asked questions in Facebook communities or the Slack channel (https://t.me/golangtw), so I decided to organize them into this article, hoping that more people can understand and get answers through searching. Since there are quite a few frequently asked questions, this is a series of compilations, and I hope to provide a more in-depth understanding by organizing them into articles.
The first article is about Type Assertion, and I hope everyone can understand more about type conversion.
Related series of articles:
Type Assertion:
Example code: https://play.golang.org/p/Ya8tVYmdpko
Excuse me,
I would like to ask about this part:
resp, ok := datum.(*module.Response)
What does the "ok" mean?
Does it mean that the interface "datum" can be successfully converted to the struct "Request"?
This usage is called Type Assertion (Go Tour has related explanations), which is mainly used for type conversion judgments. The main advantage of using Type Assertion is that you can confirm whether the conversion is successful.
Of course, reflect can also convert values, but it is more suitable when you get a parameter but don't know which data type was used initially. Then, use the reflect package to get the type and the content of the value.
In a simpler example:
func parseInterfceToString(in interface{}) string {
if val, ok := in.(string); ok {
return val
}
return ""
}
In the example above, because it is already confirmed that only string parsing is supported, you can directly use the type assertion method to convert the address. However, in many cases, if you want to support multiple types and be able to read the values correctly, what should you do?
func createQuery(q interface{}) {
t := reflect.TypeOf(q)
v := reflect.ValueOf(q)
fmt.Println("Type ", t)
fmt.Println("Value ", v)
}
This is a very simple reflect example that allows you to know the data type and actual data of the input. You can refer to the following example to process by directly using reflect.Type.Kind() to get the type:
func examiner(t reflect.Type, depth int) {
fmt.Println(strings.Repeat("\t", depth), "Type is", t.Name(), "and kind is", t.Kind())
switch t.Kind() {
case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
fmt.Println(strings.Repeat("\t", depth+1), "Contained type:")
examiner(t.Elem(), depth+1)
case reflect.Struct:
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
fmt.Println(strings.Repeat("\t", depth+1), "Field", i+1, "name is", f.Name, "type is", f.Type.Name(), "and kind is", f.Type.Kind())
if f.Tag != "" {
fmt.Println(strings.Repeat("\t", depth+2), "Tag is", f.Tag)
fmt.Println(strings.Repeat("\t", depth+2), "tag1 is", f.Tag.Get("tag1"), "tag2 is", f.Tag.Get("tag2"))
}
}
}
}
This example continues to parse inside based on different types (array, channel, map), and if it is a struct, it prints the related structure.
However, it is worth noting that if you need to truly convert the data type to that type, it is still safer to use type assertion. Otherwise, converting by using reflect.Value to get values will, by default, panic.
Conclusion:
If you only support the processing of certain types, it is recommended to use type assertion directly for type conversion, which can be easily completed. If you want to handle more types (slice, struct) and type conversion, you may have to process them slowly through reflect.
I also hope that the related information I have compiled can help everyone.
Top comments (0)