CAP 06 · LEC 02·Interfaces

`any`, type assertions y `type switch`

`any` es una interfaz vacía que acepta cualquier valor. Para recuperar el tipo concreto necesitas una type assertion o un type switch — y conviene saber cuándo evitarlas.

● INTERMEDIO6 min lecturapor Fernando Herrera · actualizado mayo de 2026
¿Encontraste un error o algo que mejorar?Editá esta lección en GitHub →

`any` es la interfaz vacía

Desde Go 1.18, any es un alias del tipo interface{} — una interfaz sin métodos. Como cualquier tipo tiene cero o más métodos, cualquier tipo satisface interface{}. Es la forma idiomática actual de aceptar valores arbitrarios.

package main import "fmt" // describe acepta cualquier valor func describe(x any) { fmt.Printf("type=%T value=%v\n", x, x) } func main() { describe(42) describe("hola") describe(3.14) describe([]int{1, 2, 3}) // any y interface{} son el mismo tipo var a any = "x" var b interface{} = a fmt.Println(b) // x }
Salidatype=int value=42 type=string value=hola type=float64 value=3.14 type=[]int value=[1 2 3] x

Type assertion: `v, ok := x.(T)`

Para extraer el valor concreto desde un any se usa una type assertion. La forma con dos retornos (v, ok) nunca falla: si el tipo no coincide, ok es false y v es el valor cero.

package main import "fmt" func main() { var x any = "hola Go" // Forma segura: dos valores, ok indica si tuvo éxito if s, ok := x.(string); ok { fmt.Println("es string:", s, "len=", len(s)) } if n, ok := x.(int); ok { fmt.Println("es int:", n) } else { fmt.Println("no era int, valor cero:", n) } }
Salidaes string: hola Go len= 8 no era int, valor cero: 0
Sin `ok` hay panic

La forma s := x.(string) (un solo retorno) panickea si el tipo no coincide. Úsala solo cuando estés seguro del tipo concreto; en código defensivo prefiere siempre v, ok := x.(T).

`type switch` para varios tipos

Cuando necesitas ramificar por tipo, un type switch es mucho más legible que una cadena de type assertions. La sintaxis especial x.(type) solo se permite dentro de switch.

package main import "fmt" func describe(x any) string { switch v := x.(type) { case int: return fmt.Sprintf("int: %d (doble = %d)", v, v*2) case string: return fmt.Sprintf("string: %q (len = %d)", v, len(v)) case []int: return fmt.Sprintf("[]int con %d elementos", len(v)) case nil: return "nil" default: return fmt.Sprintf("tipo desconocido: %T", v) } } func main() { for _, x := range []any{1, "go", []int{1, 2}, 3.14, nil} { fmt.Println(describe(x)) } }
Salidaint: 1 (doble = 2) string: "go" (len = 2) []int con 2 elementos tipo desconocido: float64 nil

Cuándo evitar `any`

any es útil para librerías generales (fmt.Println, json.Unmarshal, contenedores genéricos), pero abusar de él convierte tu código en un Python sin tipos: pierdes la ayuda del compilador. Antes de usarlo, pregúntate:

  • ¿Puedo declarar una interfaz pequeña con el método que necesito? Casi siempre sí.
  • ¿Puedo usar generics (Go 1.18+) para preservar el tipo? Si el tipo es uniforme, sí.
  • ¿Estoy haciendo type switch en muchos sitios? Es una señal de diseño OOP forzado — refactoriza a interfaz con métodos.
package main import "fmt" // MAL: any obliga a type switch en cada uso func areaAny(x any) float64 { switch v := x.(type) { case float64: return v * v default: _ = v return 0 } } // BIEN: interfaz pequeña, polimorfismo natural type Shape interface { Area() float64 } type Square struct{ Side float64 } func (s Square) Area() float64 { return s.Side * s.Side } func main() { fmt.Println(areaAny(3.0)) // 9 fmt.Println(Square{3}.Area()) // 9 }
Salida9 9