types - switch - pointer in go
¿Por qué puedo escribir funciones de alias y usarlas sin conversión? (2)
En Go, si define un nuevo tipo, por ejemplo:
type MyInt int
No puede pasar un MyInt
a una función esperando un int, o viceversa:
func test(i MyInt) {
//do something with i
}
func main() {
anInt := 0
test(anInt) //doesn''t work, int is not of type MyInt
}
Multa. ¿Pero por qué es que lo mismo no se aplica a las funciones? p.ej:
type MyFunc func(i int)
func (m MyFunc) Run(i int) {
m(i)
}
func run(f MyFunc, i int) {
f.Run(i)
}
func main() {
var newfunc func(int) //explicit declaration
newfunc = func(i int) {
fmt.Println(i)
}
run(newfunc, 10) //works just fine, even though types seem to differ
}
Ahora, no me estoy quejando porque me ahorra tener que lanzar explícitamente newfunc
para escribir MyFunc
, como tendría que hacer en el primer ejemplo; simplemente parece inconsistente. Estoy seguro de que hay una buena razón para eso; ¿alguien puede iluminarme?
La razón por la que pregunto es principalmente porque me gustaría acortar algunos de mis tipos de funciones bastante largas de esta manera, pero quiero asegurarme de que se espera y sea aceptable hacerlo :)
Resulta que este es un malentendido que tuve sobre cómo lidiar con los tipos de Go, que se puede resolver leyendo la parte relevante de la especificación:
http://golang.org/ref/spec#Type_identity
La distinción relevante de la que no tenía conocimiento era la de los tipos con nombre y sin nombre .
Los tipos con nombre son tipos con un nombre, como int, int64, float, string, bool. Además, cualquier tipo que cree utilizando ''tipo'' es un tipo con nombre.
Los tipos sin nombre son aquellos como [] cadena, cadena de mapa [cadena], [4] int. No tienen nombre, simplemente una descripción correspondiente a cómo se deben estructurar.
Si compara dos tipos con nombre, los nombres deben coincidir para que sean intercambiables. Si compara un nombre y un tipo sin nombre, siempre y cuando la representación subyacente coincida , ¡ya está listo!
por ejemplo, dado los siguientes tipos:
type MyInt int
type MyMap map[int]int
type MySlice []int
type MyFunc func(int)
el siguiente no es válido:
var i int = 2
var i2 MyInt = 4
i = i2 //both named (int and MyInt) and names don''t match, so invalid
lo siguiente está bien:
is := make([]int)
m := make(map[int]int)
f := func(i int){}
//OK: comparing named and unnamed type, and underlying representation
//is the same:
func doSlice(input MySlice){...}
doSlice(is)
func doMap(input MyMap){...}
doMap(m)
func doFunc(input MyFunc){...}
doFunc(f)
Estoy un poco desanimado. No lo sabía antes, ¡así que espero que aclare un poco el alboroto tipo para alguien más! Y significa mucho menos casting de lo que pensé en un principio :)
Tanto la pregunta como la respuesta son bastante esclarecedoras. Sin embargo, me gustaría mencionar una distinción que no está clara en la respuesta de Lytnus.
El tipo con nombre es diferente del tipo sin nombre .
La variable del tipo nombrado es asignable a la variable del tipo sin nombre , viceversa.
Las variables de diferentes tipos de nombres no son asignables entre sí.
http://play.golang.org/p/uaYHEnofT9
import (
"fmt"
"reflect"
)
type T1 []string
type T2 []string
func main() {
foo0 := []string{}
foo1 := T1{}
foo2 := T2{}
fmt.Println(reflect.TypeOf(foo0))
fmt.Println(reflect.TypeOf(foo1))
fmt.Println(reflect.TypeOf(foo2))
// Output:
// []string
// main.T1
// main.T2
// foo0 can be assigned to foo1, vice versa
foo1 = foo0
foo0 = foo1
// foo2 cannot be assigned to foo1
// prog.go:28: cannot use foo2 (type T2) as type T1 in assignment
// foo1 = foo2
}