2011-06-16 166 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