How to determine an interface{} value's “real” type?

前端 未结 7 1168
青春惊慌失措
青春惊慌失措 2020-12-22 17:15

I have not found a good resource for using interface{} types. For example

package main

import \"fmt\"

func weirdFunc(i int) interface{} {
             


        
相关标签:
7条回答
  • 2020-12-22 17:19

    There are multiple ways to get a string representation of a type. Switches can also be used with user types:

    var user interface{}
    user = User{name: "Eugene"}
    
    // .(type) can only be used inside a switch
    switch v := user.(type) {
    case int:
        // Built-in types are possible (int, float64, string, etc.)
        fmt.Printf("Integer: %v", v)
    case User:
        // User defined types work as well  
        fmt.Printf("It's a user: %s\n", user.(User).name)
    }
    
    // You can use reflection to get *reflect.rtype
    userType := reflect.TypeOf(user)
    fmt.Printf("%+v\n", userType)
    
    // You can also use %T to get a string value
    fmt.Printf("%T", user)
    
    // You can even get it into a string
    userTypeAsString := fmt.Sprintf("%T", user)
    
    if userTypeAsString == "main.User" {
        fmt.Printf("\nIt's definitely a user")
    }
    

    Link to a playground: https://play.golang.org/p/VDeNDUd9uK6

    0 讨论(0)
  • 2020-12-22 17:25

    You can use reflection (reflect.TypeOf()) to get the type of something, and the value it gives (Type) has a string representation (String method) that you can print.

    0 讨论(0)
  • 2020-12-22 17:29

    Here is an example of decoding a generic map using both switch and reflection, so if you don't match the type, use reflection to figure it out and then add the type in next time.

    var data map[string]interface {}
    
    ...
    
    for k, v := range data {
        fmt.Printf("pair:%s\t%s\n", k, v)   
    
        switch t := v.(type) {
        case int:
            fmt.Printf("Integer: %v\n", t)
        case float64:
            fmt.Printf("Float64: %v\n", t)
        case string:
            fmt.Printf("String: %v\n", t)
        case bool:
            fmt.Printf("Bool: %v\n", t)
        case []interface {}:
            for i,n := range t {
                fmt.Printf("Item: %v= %v\n", i, n)
            }
        default:
            var r = reflect.TypeOf(t)
            fmt.Printf("Other:%v\n", r)             
        }
    }
    
    0 讨论(0)
  • 2020-12-22 17:30

    You also can do type switches:

    switch v := myInterface.(type) {
    case int:
        // v is an int here, so e.g. v + 1 is possible.
        fmt.Printf("Integer: %v", v)
    case float64:
        // v is a float64 here, so e.g. v + 1.0 is possible.
        fmt.Printf("Float64: %v", v)
    case string:
        // v is a string here, so e.g. v + " Yeah!" is possible.
        fmt.Printf("String: %v", v)
    default:
        // And here I'm feeling dumb. ;)
        fmt.Printf("I don't know, ask stackoverflow.")
    }
    
    0 讨论(0)
  • 2020-12-22 17:31

    Type switches can also be used with reflection stuff:

    var str = "hello!"
    var obj = reflect.ValueOf(&str)
    
    switch obj.Elem().Interface().(type) {
    case string:
        log.Println("obj contains a pointer to a string")
    default:
        log.Println("obj contains something else")
    }
    
    0 讨论(0)
  • 2020-12-22 17:35

    I'm going to offer up a way to return a boolean based on passing an argument of a reflection Kinds to a local type receiver (because I couldn't find anything like this).

    First, we declare our anonymous type of type reflect.Value:

    type AnonymousType reflect.Value
    

    Then we add a builder for our local type AnonymousType which can take in any potential type (as an interface):

    func ToAnonymousType(obj interface{}) AnonymousType {
        return AnonymousType(reflect.ValueOf(obj))
    }
    

    Then we add a function for our AnonymousType struct which asserts against a reflect.Kind:

    func (a AnonymousType) IsA(typeToAssert reflect.Kind) bool {
        return typeToAssert == reflect.Value(a).Kind()
    }
    

    This allows us to call the following:

    var f float64 = 3.4
    
    anon := ToAnonymousType(f)
    
    if anon.IsA(reflect.String) {
        fmt.Println("Its A String!")
    } else if anon.IsA(reflect.Float32) {
        fmt.Println("Its A Float32!")
    } else if anon.IsA(reflect.Float64) {
        fmt.Println("Its A Float64!")
    } else {
        fmt.Println("Failed")
    }
    

    Can see a longer, working version here:https://play.golang.org/p/EIAp0z62B7

    0 讨论(0)
提交回复
热议问题