Voir cet extrait de je.
Code pertinent:
type somethingFuncy func(int) bool
func funcy(i int) bool {
return i%2 == 0
}
var a interface{} = funcy
func main() {
_ = a.(func(int) bool) // Works
fmt.Println("Awesome -- apparently, literally specifying the func signature works.")
_ = a.(somethingFuncy) // Panics
fmt.Println("Darn -- doesn't get here. But somethingFuncy is the same signature as func(int) bool.")
}
La première distribution fonctionne, en déclarant explicitement le type. Mais le deuxième casting panique. Pourquoi? Existe-t-il un moyen propre de diffuser une signature func plus longue?
Pour les assertions de type (que vous utilisez), seul le type réel est important. Donc somethingFuncy
est seulement égal à somethingFuncy
et non à func(int) bool
.
Pour commencer, cela n'a rien à voir avec le casting. Il n'y a pas de casting. Il y a assertions de type et conversions de type .
Vous avez affaire à une assertion de type et supposez que les mêmes conditions s'appliquent aux conversions de type . J'ai fait la même erreur en lisant votre question, mais il y a en fait une énorme différence de comportement.
Supposons que vous ayez deux types, dites int
et type MyInt int
. Ceux-ci sont convertibles car ils partagent tous les deux le même type sous-jacent (l'une des règles de conversion), donc cela fonctionne ( play ):
var a int = 10
var b MyInt = MyInt(a)
Supposons maintenant que a
ne soit pas de type int
mais de type interface{}
( play ):
var a interface{} = int(10)
var b MyInt = MyInt(a)
Le compilateur vous dira:
ne peut pas convertir un (type interface {}) en type MyInt: besoin d'une assertion de type
Alors maintenant, nous ne faisons plus conversions mais assertions. Nous devons le faire ( play ):
var a interface{} = int(10)
var b MyInt = a.(MyInt)
Nous avons maintenant le même problème que dans votre question. Cette affirmation échoue avec cette panique:
panique: conversion d'interface: l'interface est int, pas principale.
La raison en est indiquée dans la section assertions de type de la spécification:
Pour une expression x de type interface et un type
T
, l'expression primairex.(T)
affirme quex
n'est pasnil
et que la valeur stockée dansx
est de typeT
. La notationx.(T)
est appelée une assertion de type. Plus précisément, siT
n'est pas un type d'interface,x.(T)
affirme que le type dynamique dex
est identique au typeT
.
Donc int
doit être identique à MyInt
. Les règles de type identité indiquent que (entre autres règles):
Deux types nommés sont identiques si leurs noms de type proviennent de la même TypeSpec.
Comme int
et MyInt
ont des déclarations différentes ( TypeSpecs ), elles ne sont pas égales et l'assertion échoue. Lorsque vous affirmez a
à int
, l'assertion fonctionne. Donc ce que vous faites n'est pas possible.
La vérification réelle se produit dans ce code , qui vérifie simplement si les deux types sont identiques, comme prévu.
Avec les assertions de type dans Go 1.9, vous pouvez simplement ajouter =
Où vous définissez le type.
type somethingFuncy = func(int) bool
Cela indique au compilateur que somethingFuncy
est un autre nom pour func(int) bool
.
Juste pour compléter la réponse impressionnante de Nemo, notez que même si vous ne pouvez pas sauter directement à partir d'une interface (par exemple, interface{}
) d'un type dynamique donné (par exemple, int
) vers un autre type (par exemple, type MyInt int
), vous pouvez effectuer les deux étapes l'une après l'autre:
Notez que puisque le type sous-jacent est, comme son nom l'indique, dynamique , c'est une bonne idée de tester si l'assertion de type a réussi ou échoué. D'autre part, l'exactitude de la conversion de type est appliquée par le compilateur.
Voici votre extrait de terrain de jeu légèrement modifié: http://play.golang.org/p/FZv06Zf7xi
Je crois que cet alias de type est ce que vous voulez. La proposition est acceptée et devrait être dans Go 1.9. C'est à dire.
TypeSpec = identifier [ "=" ] Type .
Les références
https://github.com/golang/go/issues/181
https://github.com/golang/proposal/blob/master/design/18130-type-alias.md