web-dev-qa-db-fra.com

utiliser la réflexion dans Go pour obtenir le nom d'une structure

J'ai trouvé cette question avec ces excellentes réponses:

Comment trouver un type d'objet à Golang?

J'ai joué avec la réponse et j'ai essayé d'obtenir le nom d'une structure de la même manière:

package main

import (
        "fmt"
        "reflect"
)

type Ab struct {

}

func getType(myvar interface{}) string {
        return reflect.TypeOf(myvar).Name()
}

func main() {
        fmt.Println("Hello, playground")

        tst := "string"
        tst2 := 10
        tst3 := 1.2
        tst4 := new(Ab)

        fmt.Println(getType(tst))
        fmt.Println(getType(tst2))
        fmt.Println(getType(tst3))
        fmt.Println(getType(tst4))

}

Allez aire de jeux: http://play.golang.org/p/tD8mygvETH

Mais la sortie est:

Hello, playground
string
int
float64


Program exited.

La sortie attendue serait:

Hello, playground
string
int
float64
Ab

Program exited.

J'ai essayé de comprendre en lisant la documentation mais je n'ai pas trouvé le problème à ce sujet. Donc, désolé pour la question très générale, mais:

Quelle est la raison, reflect.TypeOf().Name() ne fonctionne pas avec (cette) structure (s)?

21
Daniele D

Dans votre exemple, vous passez une valeur de type pointeur (*Ab), Pas un type struct.

S'en tenir à Type.Name()

S'il ne s'agit pas d'un pointeur, Type.Name() renverra correctement Ab. En cas de pointeur si vous voulez toujours le nom de la structure, vous pouvez utiliser Type.Elem() pour obtenir le type de l'élément:

func getType(myvar interface{}) string {
    if t := reflect.TypeOf(myvar); t.Kind() == reflect.Ptr {
        return "*" + t.Elem().Name()
    } else {
        return t.Name()
    }
}

Le tester:

tst4 := Ab{}
tst5 := new(Ab)
fmt.Println(getType(tst4))
fmt.Println(getType(tst5))

Sortie (essayez votre exemple modifié sur le Go Playground ):

Ab
*Ab

Remarque:

Notez que comme Type.Name() ne résout pas les pointeurs, cela ne fonctionnerait pas si la valeur transmise est un pointeur à pointeur, par ex. **Ab, Alors que Type.String() résout automatiquement les pointeurs, cela fonctionnerait aussi dans ce cas.

Nous pouvons facilement faire fonctionner notre fonction getType() avec **Ab (Ou avec n'importe quelle profondeur de pointeurs):

func getType(myvar interface{}) (res string) {
    t := reflect.TypeOf(myvar)
    for t.Kind() == reflect.Ptr {
        t = t.Elem()
        res += "*"
    }
    return res + t.Name()
}

L'appeler avec des valeurs:

tst4 := Ab{}
tst5 := new(Ab)
tst6 := &tst5 // type of **Ab
tst7 := &tst6 // type of ***Ab

Sortie (essayez-le sur Go Playground ):

Ab
*Ab
**Ab
***Ab

Utilisation de Type.String()

Une approche plus simple et meilleure consisterait à utiliser Type.String() au lieu de Type.Name() qui gère automatiquement les pointeurs et inclut également le nom du package. Par exemple.:

func getType(myvar interface{}) string {
    return reflect.TypeOf(myvar).String()
}

Pour l'exemple modifié, il génère:

string
int
float64
main.Ab
*main.Ab

Essayez cette variante sur le Go Playground .

44
icza

fmt a un cool %T tag également

package main

import (
    "fmt"
    "net/http"
)

type Potato struct {
}

func main() {
    fmt.Printf("I have a %T, an %T and a %T\n", Potato{}, http.StatusMultipleChoices, &http.Response{})
}

les sorties I have a main.Potato, an int and a *http.Responsehttps://play.golang.org/p/6z7_0BSitm

6
Azr

Le problème est que new renvoie un pointeur, ce qui suit devrait obtenir le résultat souhaité.

package main

import (
    "fmt"
    "reflect"
)

type Ab struct {
}

func getType(myvar interface{}) {
    valueOf := reflect.ValueOf(myvar)

    if valueOf.Type().Kind() == reflect.Ptr {
        fmt.Println(reflect.Indirect(valueOf).Type().Name())
    } else {
        fmt.Println(valueOf.Type().Name())
    }
}

func main() {
    fmt.Println("Hello, playground")

    tst := "string"
    tst2 := 10
    tst3 := 1.2
    tst4 := new(Ab)

    getType(tst)
    getType(tst2)
    getType(tst3)
    getType(tst4)

}

La sortie est

Hello, playground
string
int
float64
Ab
2
sfault