2011-08-09 324 views
32

我必須聲明如下如何在運行時檢查變量類型在Go語言

CURLcode curl_wrapper_easy_setopt_long(CURL* curl, CURLoption option, long param); 
CURLcode curl_wrapper_easy_setopt_str(CURL* curl, CURLoption option, char* param); 

幾個C函數,我想揭露那些像這樣

func (e *Easy)SetOption(option Option, param interface{}) 

,所以我需要一個去功能能夠在運行時檢查參數類型。我該怎麼做,這是一個好主意(如果不是這種情況下的良好做法)?

回答

11

見類型斷言這裏:

http://golang.org/ref/spec#Type_assertions

我主張一個明智的類型(字符串,UINT64)只有等,並將其作爲鬆散越好,執行轉換到最後的原生型。

+9

答案應該是完整的,而不僅僅是鏈接。請充實這個答案。 – Flimzy

+2

注意:這不適用於具體類型,只適用於接口類型。 – darethas

-1

這有什麼錯

func (e *Easy)SetStringOption(option Option, param string) 
func (e *Easy)SetLongOption(option Option, param long) 

等等?

+0

,因爲在libCURL庫中只有一個用於選項設置的函數curl_easy_setopt(CURL * curl,CURLoption選項,...)。但cgo不支持可變參數,所以我在C中爲每種類型的參數提供了包裝函數。我認爲Go界面應該儘可能接近C點。如果用戶知道libCURL(來自C語言或其他語言),我希望他在家中感覺正確;) –

+0

遊戲後期,但我會反對這種做法!您希望圖書館能夠感受到* Go *用戶的家。 (像cURL這樣的低級庫的直接端口混淆了人的最好例子是... PHP) – Nevir

47

看來,圍棋有開關的特殊形式奉獻給這個(它被稱爲型開關):

func (e *Easy)SetOption(option Option, param interface{}) { 

    switch v := param.(type) { 
    default: 
     fmt.Printf("unexpected type %T", v) 
    case uint64: 
     e.code = Code(C.curl_wrapper_easy_setopt_long(e.curl, C.CURLoption(option), C.long(v))) 
    case string: 
     e.code = Code(C.curl_wrapper_easy_setopt_str(e.curl, C.CURLoption(option), C.CString(v))) 
    } 
} 
+0

這個語法只能用在'switch'中嗎?例如,如果我只關心1個案例,可能是一個交換機過度殺傷? –

+0

@NathanH是的,這種方式只適用於開關(用Go 1.10測試) – MewX

36

通過@Darius答案是最地道的(也可能是更好的性能)的方法。一個限制是你正在檢查的類型必須是interface{}。如果您使用混凝土類型,則會失敗。

另一種在運行時確定某些東西的方法,包括具體類型,就是使用Go reflect包。鏈接TypeOf(x).Kind()在一起,你可以得到一個reflect.Kind值,它是一個uint類型:http://golang.org/pkg/reflect/#Kind

然後,您可以做類型檢查開關塊之外,像這樣:

import (
    "fmt" 
    "reflect" 
) 

// .... 

x := 42 
y := float32(43.3) 
z := "hello" 

xt := reflect.TypeOf(x).Kind() 
yt := reflect.TypeOf(y).Kind() 
zt := reflect.TypeOf(z).Kind() 

fmt.Printf("%T: %s\n", xt, xt) 
fmt.Printf("%T: %s\n", yt, yt) 
fmt.Printf("%T: %s\n", zt, zt) 

if xt == reflect.Int { 
    println(">> x is int") 
} 
if yt == reflect.Float32 { 
    println(">> y is float32") 
} 
if zt == reflect.String { 
    println(">> z is string") 
} 

它打印出局:

reflect.Kind: int 
reflect.Kind: float32 
reflect.Kind: string 
>> x is int 
>> y is float32 
>> z is string 

再一次,這可能不是首選的方法,但很好了解其他選項。

+0

爲什麼你需要'.Kind()'?它沒有它的作品。 – karantan

+0

@karantan根據quux00的代碼.Kind()是必需的。否則,你會得到編譯時錯誤。 https://golang.org/pkg/reflect/#Kind類型表示類型代表的特定類型 https://golang.org/pkg/reflect/#TypeOf返回類型interface {} – Mujibur

0

quux00的答案只講述了比較基本類型。

如果您需要比較您定義的類型,則不應使用reflect.TypeOf(xxx)。相反,請使用reflect.TypeOf(xxx).Kind()

有兩類類型:

  • 直接類型(你直接定義的類型)
  • 基本類型(int,float64,結構,...)

這是一個完整的例子:

type MyFloat float64 
type Vertex struct { 
    X, Y float64 
} 

type EmptyInterface interface {} 

type Abser interface { 
    Abs() float64 
} 

func (v Vertex) Abs() float64 { 
    return math.Sqrt(v.X*v.X + v.Y*v.Y) 
} 

func (f MyFloat) Abs() float64 { 
    return math.Abs(float64(f)) 
} 

var ia, ib Abser 
ia = Vertex{1, 2} 
ib = MyFloat(1) 
fmt.Println(reflect.TypeOf(ia)) 
fmt.Println(reflect.TypeOf(ia).Kind()) 
fmt.Println(reflect.TypeOf(ib)) 
fmt.Println(reflect.TypeOf(ib).Kind()) 

if reflect.TypeOf(ia) != reflect.TypeOf(ib) { 
    fmt.Println("Not equal typeOf") 
} 
if reflect.TypeOf(ia).Kind() != reflect.TypeOf(ib).Kind() { 
    fmt.Println("Not equal kind") 
} 

ib = Vertex{3, 4} 
if reflect.TypeOf(ia) == reflect.TypeOf(ib) { 
    fmt.Println("Equal typeOf") 
} 
if reflect.TypeOf(ia).Kind() == reflect.TypeOf(ib).Kind() { 
    fmt.Println("Equal kind") 
} 

輸出將是:

main.Vertex 
struct 
main.MyFloat 
float64 
Not equal typeOf 
Not equal kind 
Equal typeOf 
Equal kind 

正如你所看到的,reflect.TypeOf(xxx)返回直接類型,你可能想使用,而reflect.TypeOf(xxx).Kind()返回基本類型。


下面是結論。如果您需要與基本類型進行比較,請使用reflect.TypeOf(xxx).Kind();如果您需要與自定義類型進行比較,請使用reflect.TypeOf(xxx)

if reflect.TypeOf(ia) == reflect.TypeOf(Vertex{}) { 
    fmt.Println("self-defined") 
} else if reflect.TypeOf(ia).Kind() == reflect.Float64 { 
    fmt.Println("basic types") 
} 
相關問題