---
id: 548504c5a0b4857763527603f3e1059e
author: snowmerak
title: Any no es Any, pero Any es Any
description: Este documento analiza en detalle el tipo `any` del lenguaje Go y su estructura interna `EFace`, y explica los métodos de manejo dinámico de tipos mediante el paquete `reflect` y las aserciones y los switches de tipo.
language: es
date: 2025-09-30T15:12:53.689280321Z
path: /blog/posts/any-is-not-any-but-any-is-any-z6161856d
category: language
---

## Any

En el lenguaje Go, el tipo any es un alias de `interface{}`, una interfaz mágica capaz de contener cualquier tipo. En otras palabras, cualquier tipo puede asignarse a una variable de tipo any.

```go
var a any
a = 42          // int
a = "hello"     // string
a = true        // bool
a = 3.14        // float64
```

Así, el tipo any puede contener valores de diversos tipos, lo que permite escribir código flexible. Sin embargo, al utilizar el tipo any hay algunos puntos que requieren atención.

### Type Assertion

Para utilizar el valor real de una variable de tipo any, es necesario emplear una aserción de tipo (type assertion). La aserción de tipo cumple la función de indicar al compilador que la variable any es de un tipo específico.

```go
var a any = "hello"
str, ok := a.(string)
if ok {
    fmt.Println("String value:", str)
} else {
    fmt.Println("Not a string")
}
```

En el ejemplo anterior, `a.(string)` afirma que `a` es de tipo string. Si `a` no es de tipo string, `ok` será false, lo que permite evitar que el programa entre en pánico.

### Type Switch

El type switch (switch de tipos) permite ejecutar distintos comportamientos según el tipo real de una variable de tipo any. Resulta útil cuando es necesario procesar varios tipos.

```go
var a any = 42
switch v := a.(type) {
case int:
    fmt.Println("Integer:", v)
case string:
    fmt.Println("String:", v)
case bool:
    fmt.Println("Boolean:", v)
default:
    fmt.Println("Unknown type")
}
```

En el ejemplo anterior, `a.(type)` examina el tipo real de `a` y ejecuta el caso correspondiente a ese tipo.

### Reflection

Mediante el paquete reflect de Go, es posible examinar y manipular dinámicamente en tiempo de ejecución el tipo y el valor de una variable de tipo any. Esto resulta útil al trabajar con estructuras de datos complejas.

```go
import (
    "fmt"
    "reflect"
)

var a any = 3.14
v := reflect.ValueOf(a)
fmt.Println("Type:", v.Type())
fmt.Println("Value:", v.Float())
```

En el ejemplo anterior, mediante el paquete reflect se pueden comprobar en tiempo de ejecución el tipo y el valor de `a`.

## EFace

En el lenguaje Go, las interfaces se dividen en dos formas principales: EFace (Empty Interface) e IFace (Interface with Methods). De ellas, EFace es el concepto equivalente al tipo any que hemos tratado hasta ahora.

### Estructura

EFace es una estructura especial que existe únicamente dentro del runtime de Go, por lo que aquí trabajaremos con un mimic (imitación) de la misma.

```go
type runtimeTypeMimic struct {
	Size_       uintptr
	PtrBytes    uintptr // number of (prefix) bytes in the type that can contain pointers
	Hash        uint32  // hash of type; avoids computation in hash tables
	TFlag       uint8   // extra type information flags
	Align_      uint8   // alignment of variable with this type
	FieldAlign_ uint8   // alignment of struct field with this type
	Kind_       uint8   // enumeration for C
	Equal       func(unsafe.Pointer, unsafe.Pointer) bool
	GCData      *byte
	Str         int32 // string form
	PtrToThis   int32 // type for pointer to this type, may be zero
}

type eFaceMimic struct {
	Type *runtimeTypeMimic
	Data unsafe.Pointer
}
```

EFace tiene dos campos:

- `Type`: es un puntero que contiene los metadatos sobre el tipo real del valor.
- `Data`: es un puntero que contiene el valor real.

Además, EFace gestiona la información de tipos internamente mediante la estructura `runtimeType`. Esta estructura contiene diversos metadatos, como el tamaño del tipo, su alineación y su valor hash.

Dentro de ella, los aspectos que debemos observar son los campos `Kind_`, `Hash` y `Equal`. `Kind_` indica la clase del tipo, mientras que `Hash` y `Equal` se utilizan para calcular valores hash y comparar tipos en las tablas hash.

### Envoltorio

Ahora envolvamos este EFace para poder utilizar la magia negra de forma más cómoda.

```go
type TypeInfo struct {
	Hash  uint32
	TFlag uint8
	Kind  uint8
	Equal func(unsafe.Pointer, unsafe.Pointer) bool
	This  unsafe.Pointer
}

func GetTypeInfo(v any) TypeInfo {
	eface := *(*eFaceMimic)(unsafe.Pointer(&v))
	return TypeInfo{
		Hash:  eface.Type.Hash,
		TFlag: eface.Type.TFlag,
		Kind:  eface.Type.Kind_,
		Equal: eface.Type.Equal,
		This:  eface.Data,
	}
}
```

La función anterior recibe una variable de tipo any, extrae la estructura EFace interna, obtiene de ella la información de tipo y la devuelve como una estructura `TypeInfo`. Ahora, con este `TypeInfo`, se puede acceder fácilmente al valor hash del tipo, su clase, la función de comparación, etc.

### Uso

El uso es realmente sencillo. Basta con pasar una variable de tipo any a la función `GetTypeInfo`.

```go
func main() {
	i := 42
	eface := GetTypeInfo(i)
	fmt.Printf("%+v\n", eface)

	f := 3.14
	eface2 := GetTypeInfo(f)
	fmt.Printf("%+v\n", eface2)

	// Compare the two values using the Equal function from the type info
	log.Println(eface.Equal(eface.This, eface.This))
	log.Println(eface2.Equal(eface2.This, eface2.This))
	log.Println(eface2.Equal(eface.This, eface2.This))
	log.Println(eface.Equal(eface2.This, eface.This))
}
```

En el ejemplo anterior, se pasan a la función `GetTypeInfo` un valor entero y un valor de punto flotante para mostrar la información de tipo de cada uno, y se utiliza la función `Equal` para comparar los valores. De este modo, es posible obtener la información de tipo y compararla de forma más rápida.

Además, este método también puede aplicarse a estructuras, punteros, interfaces, etc., y permite resolver el problema, nada infrecuente, del nil con tipo (typed nil). `Hash` tiene asignado un valor siempre que existe un tipo, mientras que `This` vale 0 si es nil, por lo que es posible distinguirlos.

## Conclusión

EFace desempeña un papel importante en el manejo del tipo any en el lenguaje Go actual. Gracias a él, es posible procesar valores de diversos tipos de forma flexible y rápida, así como obtener y utilizar información detallada sobre los tipos. No obstante, se trata de una funcionalidad oculta dentro del runtime, que puede verse afectada por cambios en la especificación del lenguaje, por lo que debe utilizarse con precaución.
