111 votes

Comment vérifier le type d'une variable à l'exécution en langage Go

J'ai quelques fonctions C déclarées comme ceci

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

Je voudrais les exposer comme une fonction Go comme ceci

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

donc je dois être capable de vérifier param au moment de l'exécution. Comment puis-je faire cela et est-ce une bonne idée (sinon, quelle est la bonne pratique dans ce cas) ?

139voto

Darius Kucinskas Points 2550

Il semble que Go ait une forme spéciale de commutateur dédié à cela (il est appelé commutateur de type ):

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

72voto

quux00 Points 2496

La réponse de @Darius est la méthode la plus idiomatique (et probablement la plus performante). Une limitation est que le type que vous vérifiez doit être de type interface{} . Si vous utilisez un type de béton, il échouera.

Une autre façon de déterminer le type d'un élément au moment de l'exécution, y compris les types concrets, est d'utiliser la fonction Go reflect paquet. Chaînage TypeOf(x).Kind() ensemble, vous pouvez obtenir un reflect.Kind qui est une valeur uint type : http://golang.org/pkg/reflect/#Kind

Vous pouvez ensuite effectuer des vérifications pour les types en dehors d'un bloc de commutation, comme suit :

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

Qui imprime des sorties :

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

Encore une fois, ce n'est probablement pas la meilleure façon de procéder, mais il est bon de connaître les autres options.

27voto

MewX Points 2321

La réponse de quux00 ne parle que de la comparaison des types de base.

Si vous avez besoin de comparer des types que vous avez définis, vous ne devriez pas utiliser reflect.TypeOf(xxx) . Au lieu de cela, utilisez reflect.TypeOf(xxx).Kind() .

Il existe deux catégories de types :

  • les types directs (les types que vous avez définis directement)
  • types de base (int, float64, struct, ...)

Voici un exemple complet :

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

La sortie serait :

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

Comme vous pouvez le voir, reflect.TypeOf(xxx) renvoie les types directs que vous pourriez vouloir utiliser, tandis que reflect.TypeOf(xxx).Kind() renvoie les types de base.


Voici la conclusion. Si vous avez besoin de comparer avec des types de base, utilisez reflect.TypeOf(xxx).Kind() ; et si vous avez besoin de comparer avec des types auto-définis, utilisez 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")
}

27voto

Deleted Points 2693

Voir les assertions de type ici :

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

J'affirmerais un type raisonnable (string, uint64) etc. et je le garderais aussi lâche que possible, en effectuant une conversion vers le type natif en dernier.

0voto

kostix Points 11762

Quel est le problème avec

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

et ainsi de suite ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X