types - keywords - ¿Cómo convertir a un alias de tipo en Go?
meta tags seo 2018 (4)
Ver este fragmento de patio de recreo .
Código relevante:
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.")
}
El primer reparto funciona, declarando explícitamente el tipo. Pero el segundo elenco entra en pánico. ¿Por qué? ¿Hay una forma limpia de convertir a una firma de función más larga?
Actualización 2017:
Con las aserciones de tipo en Go 1.9, simplemente puede agregar =
donde define el tipo.
type somethingFuncy = func(int) bool
Esto le dice al compilador que somethingFuncy
es un nombre alternativo para func(int) bool
.
tl; dr
Para las aserciones de tipo (que usa), solo importa el tipo real. Así que somethingFuncy
solo es igual a somethingFuncy
y no a func(int) bool
.
Explicación
Para empezar, esto no tiene nada que ver con el casting. No hay casting en marcha. Hay aserciones de tipo y conversiones de tipo .
Usted está tratando con una aseveración de tipo y está asumiendo que las mismas condiciones son válidas para las conversiones de tipo. Cometí el mismo error al leer tu pregunta, pero en realidad hay una gran diferencia en el comportamiento.
Supongamos que tiene dos tipos, digamos int
y type MyInt int
. Estos son convertibles ya que ambos comparten el mismo tipo subyacente (una de las reglas de conversión), así que esto funciona ( play ):
var a int = 10
var b MyInt = MyInt(a)
Ahora, supongamos que a
no es del tipo int
sino del tipo interface{}
( play ):
var a interface{} = int(10)
var b MyInt = MyInt(a)
El compilador te dirá:
no se puede convertir una (interfaz de tipo {}) para escribir MyInt: necesita una aserción de tipo
Así que ahora ya no estamos haciendo conversiones sino afirmaciones . Necesitamos hacer esto ( play ):
var a interface{} = int(10)
var b MyInt = a.(MyInt)
Ahora tenemos el mismo problema que en tu pregunta. Esta afirmación falla con este pánico:
pánico: conversión de interfaz: interfaz es int, no main.MyInt
El motivo de esto se establece en la sección de aseveraciones de tipo de la especificación:
Para una expresión x de tipo de interfaz y un tipo
T
, la expresión principalx.(T)
afirma quex
no esnil
y que el valor almacenado enx
es de tipoT
La notaciónx.(T)
se llama una aserción de tipo. Más precisamente, siT
no es un tipo de interfaz,x.(T)
afirma que el tipo dinámico dex
es idéntico al tipoT
Así que int
debe ser idéntico a MyInt
. Las reglas de identidad de tipo establecen que (entre otras reglas):
Dos tipos con nombre son idénticos si sus nombres de tipo se originan en la misma TypeSpec.
Como int
y MyInt
tienen diferentes declaraciones ( TypeSpecs ) no son iguales y la aserción falla. Cuando afirmas a
a int
, la aserción funciona. Entonces, lo que estás haciendo no es posible.
Prima:
La verificación real ocurre en este código , que simplemente verifica si ambos tipos son iguales, como se esperaba.
Creo que el alias de tipo es lo que quieres. La propuesta es aceptada y debe estar en Go 1.9. Es decir.
TypeSpec = identifier [ "=" ] Type .
Referencias
https://github.com/golang/go/issues/18130
https://github.com/golang/proposal/blob/master/design/18130-type-alias.md
Solo para completar la asombrosa respuesta de nemo, tenga en cuenta que si bien no puede saltar directamente de una interfaz (ef, interface{}
) de un tipo dinámico dado (por ejemplo, int
) a otro tipo (por ejemplo, type MyInt int
), puede hacerlo Los dos pasos uno tras otro:
- afirma que el tipo dinámico de tu variable es lo que esperas que sea;
- convierta el resultado de esa afirmación al tipo de su elección.
Tenga en cuenta que dado que el tipo subyacente es, como su nombre lo indica, dinámico , es una buena idea probar si la aserción de tipo tuvo éxito o no. Por otro lado, la corrección de conversión de tipo es impuesta por el compilador.
Aquí está el fragmento de su área de juego ligeramente modificado: http://play.golang.org/p/FZv06Zf7xi