2016-08-16 1 views
4

Disons que j'ai ceci:Golang: Pouvez-vous taper une interface retournée {} dans une instruction?

type Donut string 
type Muffin string 

func getPastry() (interface{}, error) { 
    // some logic - this is contrived 
    var d Donut 
    d = "Bavarian" 
    return d, nil 
} 

Est-il possible de le réduire à une ligne:

p, err := getPastry() 
thisPastry := p.(Donut) 

En d'autres termes, quelque chose comme ça, qui ne compile pas:

thisPastry, err := getPastry().(Donut, error) 

Pas que d'avoir deux lignes de code pour obtenir le "générique" et taper c'est un gros problème, mais ça me semble inutile et simple, et cela signifie généralement qu'il me manque quelque chose obvio us :-)

Répondre

7

Vous ne pouvez pas. Mieux que vous pouvez faire est d'écrire une fonction d'assistance (et faire l'affirmation de type à cela):

func getDonut(p interface{}, err error) (Donut, error) { 
    return p.(Donut), err 
} 

Et puis il devient une ligne:

d, err := getDonut(getPastry()) 

Ou vous pouvez même « intégrer » la getPastry() appel à la fonction d'aide:

func getDonutPastry() (Donut, error) { 
    p, err := getPastry() 
    return p.(Donut), err 
} 

Et puis l'appeler (une seule ligne encore plus courte):

d, err := getDonutPastry() 

Note:

Bien sûr, si la valeur retournée par getPastry() est pas de type dynamique Donut, ce sera une panique d'exécution. Pour éviter cela, vous pouvez utiliser le formulaire spécial du type assertion:

v, ok := x.(T) 

Ce qui donne une valeur booléenne typées supplémentaire. La valeur de ok est true si l'assertion est valide. Sinon, il s'agit de false et la valeur v correspond à la valeur zéro pour le type T. Aucune panique d'exécution ne se produit dans ce cas.

versions sûres des fonctions d'aide en utilisant la forme spéciale pourrait ressembler à ceci (ils renvoient une erreur plutôt que la panique):

func getDonut2(p interface{}, err error) (Donut, error) { 
    if d, ok := p.(Donut); ok { 
     return d, err 
    } else { 
     return "", errors.New("Not a Donut!") 
    } 
} 

func getDonutPastry2() (Donut, error) { 
    p, err := getPastry() 
    if d, ok := p.(Donut); ok { 
     return d, err 
    } else { 
     return "", errors.New("Not a Donut!") 
    } 
} 

Voir les questions relatives:

Return map like 'ok' in Golang on normal functions

Go: multiple value in single-value context

+2

OMI cet exemple montre les mauvaises pratiques que nous faisons une affirmation de type sans vérifier une erreur, où la fonction d'emballage donne l'impression qu'il retournera des erreurs et ne paniquera pas. – baloo

+0

@baloo Voir les réponses aux questions. – icza

+0

bonnes notes supplémentaires! – baloo

4

Réponse courte: Ce n'est pas possible. Il sera plus lisible et compréhensible par plus de gens car il n'y a pas de longues lignes enchaînant beaucoup de choses.

Dans votre exemple, je suppose que vous devrez tester une erreur et ensuite vérifier un Muffin etc. Pour le rendre super clair quels types vous attendez et ce qu'il faut faire avec eux, vous pouvez faire un commutateur de type:

thisPastry, err := getPastry() 
if err != nil { ... } 

switch v := thisPastry.(type) { 
case Donut: 
    fmt.Println(v) 
case Muffin: 
    fmt.Println(v, "mmm!") 
default: 
    // some kind of error? 
}