【问题标题】:How to determine an interface{} value's "real" type?如何确定 interface{} 值的“真实”类型?
【发布时间】:2011-09-16 09:07:05
【问题描述】:

我还没有找到使用interface{} 类型的好资源。例如

package main

import "fmt"

func weirdFunc(i int) interface{} {
    if i == 0 {
        return "zero"
    }
    return i
}
func main() {
    var i = 5
    var w = weirdFunc(5)

    // this example works!
    if tmp, ok := w.(int); ok {
        i += tmp
    }

    fmt.Println("i =", i)
}

你知道使用 Go 的 interface{} 的好介绍吗?

具体问题:

  • 如何获得 w 的“真实”类型?
  • 有什么方法可以得到一个类型的字符串表示吗?
  • 有没有办法使用一个类型的字符串表示来 转换一个值?

【问题讨论】:

    标签: types type-conversion go


    【解决方案1】:

    你也可以做类型切换:

    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.")
    }
    

    【讨论】:

    • 谢谢你。但仍然不完全存在。在示例中,如何将 var w 强制转换为 int?
    • Mue 的例子做了同样的事情,但是在一个类型切换而不是一个 if 语句中。在 'case int' 中,'v' 将是一个整数。在 'case float64' 中,'v' 将是 float64 等。
    • 正确。忘记了语法 var.(type),它偷偷摸摸而且很酷
    【解决方案2】:

    您的示例确实有效。这是一个简化版本。

    package main
    
    import "fmt"
    
    func weird(i int) interface{} {
        if i < 0 {
            return "negative"
        }
        return i
    }
    
    func main() {
        var i = 42
        if w, ok := weird(7).(int); ok {
            i += w
        }
        if w, ok := weird(-100).(int); ok {
            i += w
        }
        fmt.Println("i =", i)
    }
    
    Output:
    i = 49
    

    它使用Type assertions

    【讨论】:

    • 你说得对!谢谢!您对类型的类型字符串表示有任何见解吗?
    • 查看reflect.TypeOf
    • @DmitriGoldring 这至少回答了主题标题中的问题。这个答案不是。非常感谢。
    【解决方案3】:

    您可以使用反射 (reflect.TypeOf()) 来获取某物的类型,它给出的值 (Type) 具有可以打印的字符串表示形式(String 方法)。

    【讨论】:

    • 如果你只想得到一个字符串或一个类型(例如,为了在Mue's answer中的类型切换链接的默认块中打印,你可以使用fmt的“%T”格式而不是直接使用reflect
    【解决方案4】:

    这里是一个使用switch和reflection对泛型map进行解码的例子,所以如果你的类型不匹配,使用反射来找出它,然后在下次添加类型。

    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)             
        }
    }
    

    【讨论】:

      【解决方案5】:

      类型开关也可以和反射一起使用:

      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")
      }
      

      【讨论】:

        【解决方案6】:

        有多种方法可以获取类型的字符串表示。开关也可以与用户类型一起使用:

        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")
        }
        

        游乐场链接:https://play.golang.org/p/VDeNDUd9uK6

        【讨论】:

          【解决方案7】:

          我将提供一种基于将反射 Kinds 的参数传递给本地类型接收器来返回布尔值的方法(因为我找不到类似的东西)。

          首先,我们声明我们的匿名类型类型为 reflect.Value:

          type AnonymousType reflect.Value
          

          然后我们为我们的本地类型 AnonymousType 添加一个构建器,它可以接受任何潜在类型(作为接口):

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

          然后我们为我们的 AnonymousType 结构添加一个函数,该函数针对 reflect.Kind 进行断言:

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

          这允许我们调用以下代码:

          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")
          }
          

          可以在这里看到更长的工作版本:https://play.golang.org/p/EIAp0z62B7

          【讨论】:

            猜你喜欢
            • 2013-12-10
            • 2011-02-15
            • 1970-01-01
            • 2014-12-11
            • 2010-10-03
            • 2011-02-11
            • 1970-01-01
            • 2020-06-01
            • 1970-01-01
            相关资源
            最近更新 更多