En esta parte se complica bastante porque se juntan 2 conceptos que no se tocaron tan a detalle:
-
El tipo
func
: Es un type que es una función. Lo que hace es definir una firma definida y las funciones que cuadren con esa firma se consideran de ese tipo. Similar a los métodos de las interfaces. -
Closures: Funciones anónimas que tienen acceso al scope que las está rodeando.
Se complica un poco más porque tenemos dosfunc types
anidadas.
// CheckAuth ...
func CheckAuth() Middleware {
check := 1
fmt.Println(check) // prints: 1
return func(f http.HandlerFunc) http.HandlerFunc {
fmt.Println(check + 1) // prints: 2
return func(w http.ResponseWriter, r *http.Request) {
fmt.Println(check + 1) // prints: 2
fmt.Println("Checking authentication")
flag := false
if flag == false {
fmt.Println("Unauthorized")
return
}
f(w, r)
}
}
}
La función principal tiene la firma:
func CheckAuth() Middleware
Aquà retorna un a func type Middleware
Lo que significa que retorna una función con la firma func(http.HandlerFunc) http.HandlerFunc
. Por eso regresa la función de la manera en que vemos:
return func(f http.HandlerFunc) http.HandlerFunc
Lo relevante es que http.HandlerFunc
también es una func type
por eso debe tener en otro return la firma que tienen los handlers:
return func(w http.ResponseWriter, r *http.Request)
Asà explÃcitamente está regresando la firma definida.
Hasta aquà todo me hacia sentido, pero me preguntaba. ¿Cómo es que en main
podemos pasarla sin parámetros y en AddMiddlewares
cuando se vuelve m(f)
si lleva uno? ¿Cómo llega esa f
al final?
Luego de varios test haciendo debugging (y leer más acerca de closures), encontré que CheckAuth() se ejecutaba 3 veces dependiendo la sección y la firma con la que se llamó. Dejé los prints para experimentar como salÃa y fue asÃ.
En Main cuando se mandaba a llamar solo CheckAuth()
sin parámetros imprimÃa 1 y nada más, como si solo se inicializara la función y su scope. En AddMiddleware
se ejecutaba la función del primer return y únicamente ese scope, ya teniendo acceso a la variable check, por eso se imprimÃa 2. Mientras que al final cuando hacia el request a localhost
y ya llegaban el (writer y request) se ejecutaba la función del segundo return. Pero en esta se volvÃa a imprimir 2 porque la anterior modificación no persistÃa. Como en el ejemplo se quedaron las funciones en blanco era difÃcil de percibir, pero creo es un comportamiento interesante de las func types y confuso con tanto func type.
Un ejemplo más sencillo de visualizar:
type Add func(int) int
func adder() Add { // es decir regresa una función con firma func(int) int
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
// se manda a llamar sin recibir valores porque asi es la firma
// pareciera solo se inicializara la variable función
// asignando el valor de cero a la variable sum de dentro
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
// aquà es la verdadera implementación ya recibiendo un argumento
// y se ejecuta la funcion del return
pos(i),
neg(-2*i),
)
}
}
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?