2011-06-16 164 views
77

我还没有找到合适的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的 “真实” 的类型?
  • 有没有什么办法可以得到一个类型的字符串表示?
  • 有没有什么方法可以用一个类型的字符串表示来 转换一个值?

回答

62

你的例子确实有效。这是一个简化版本。

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

+0

你是绝对正确的!谢谢!你有任何类型的字符串表示的洞察力? – 2011-06-16 15:17:10

+4

查看'reflect.TypeOf'。 – 2014-01-19 11:21:27

83

你也可以做类型开关:

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

谢谢你。但仍不完全。在这个例子中,如何将var w强制转换为int? – 2011-06-16 15:11:04

+0

没关系。 @peterSO明白了。 – 2011-06-16 15:18:39

+3

Mue的例子做同样的事情,但在一个类型开关,而不是一个if语句。在'case int'中,'v'将是一个整数。在'case float64'中,'v'将是一个float64等 – jimt 2011-06-16 16:48:50

35

可以使用反射(reflect.TypeOf())得到的东西的类型和价值它给(Type)有一个字符串表示(String方法),您可以打印。

+5

如果你只是想获得一个字符串或类型(例如用于在[Mue的回答](http:// stackoverflow.com/a/6373523/55504)你可以使用'fmt'的'%T'格式,而不是直接使用'reflect'。 – 2015-03-10 16:49:54

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

下面是使用交换机和反射,因此,如果不匹配的类型,使用反射到数字解码的通用映射的一个例子它出来,然后在下次添加该类型。

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

我会提供了一个方法,返回基于传递一个反射类型的参数传递给本地型接收器的布尔(因为我无法找到这样的事)。

首先,我们宣布我们的匿名类型类型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