---
id: 548504c5a0b4857763527603f3e1059e
author: snowmerak
title: Any non è Any, ma Any è Any
description: Analizza in dettaglio il tipo `any` del linguaggio Go e la sua struttura interna `EFace`, e descrive i metodi di gestione dinamica dei tipi che sfruttano il pacchetto `reflect` nonché le asserzioni e gli switch di tipo.
language: it
date: 2025-09-30T15:12:53.689280321Z
path: /blog/posts/any-is-not-any-but-any-is-any-z6161856d
category: language
---

## Any

Nel linguaggio Go, il tipo any è un alias di `interface{}`, una sorta di interfaccia magica in grado di contenere valori di qualsiasi tipo. In altre parole, è possibile assegnare un valore di qualsiasi tipo a una variabile di tipo any.

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

In questo modo, il tipo any consente di contenere valori di diversi tipi, rendendo possibile la scrittura di codice flessibile. Tuttavia, quando si utilizza il tipo any, occorre prestare attenzione ad alcuni aspetti.

### Type Assertion

Per utilizzare il valore effettivo contenuto in una variabile di tipo any, è necessario ricorrere all'asserzione di tipo (type assertion). L'asserzione di tipo serve a comunicare al compilatore che la variabile di tipo any è di un determinato tipo.

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

Nell'esempio precedente, `a.(string)` asserisce che `a` è di tipo string. Se `a` non è di tipo string, `ok` assume il valore false, e in questo modo è possibile evitare che il programma vada in panic.

### Type Switch

Lo switch sui tipi (type switch) consente di eseguire operazioni diverse in base al tipo effettivo di una variabile di tipo any. È utile quando è necessario gestire più tipi.

```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")
}
```

Nell'esempio precedente, `a.(type)` verifica il tipo effettivo di `a` ed esegue il caso corrispondente a tale tipo.

### Reflection

Utilizzando il package reflect di Go, è possibile esaminare e manipolare dinamicamente, a runtime, il tipo e il valore di una variabile di tipo any. Ciò è utile quando si lavora con strutture dati complesse.

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

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

Nell'esempio precedente, il package reflect viene utilizzato per verificare a runtime il tipo e il valore di `a`.

## EFace

Nel linguaggio Go, le interfacce si dividono in due forme principali: EFace (Empty Interface) e IFace (Interface with Methods). Tra queste, EFace è il concetto equivalente al tipo any che abbiamo trattato finora.

### Struttura

EFace è una struttura speciale che esiste solo all'interno del runtime di Go; pertanto, qui la rappresenteremo tramite un mimic (mimic).

```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 possiede due campi:

- `Type`: un puntatore contenente i metadati sul tipo effettivo del valore.
- `Data`: un puntatore contenente il valore effettivo.

Inoltre, EFace gestisce le informazioni sul tipo internamente tramite la struttura `runtimeType`. Questa struttura contiene vari metadati, come la dimensione del tipo, l'allineamento e il valore di hash.

Nella struttura, i campi su cui dobbiamo concentrarci sono `Kind_`, `Hash` ed `Equal`. `Kind_` indica la categoria del tipo, mentre `Hash` ed `Equal` vengono utilizzati per calcolare il valore di hash e per confrontare i tipi nelle hash table.

### Incapsulamento

Ora avvolgiamo questo EFace in modo da poter utilizzare la magia nera in maniera più comoda.

```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 funzione precedente riceve una variabile di tipo any, estrae la struttura EFace interna, ne ricava le informazioni sul tipo e le restituisce sotto forma di struttura `TypeInfo`. Ora è possibile utilizzare `TypeInfo` per accedere facilmente al valore di hash del tipo, alla sua categoria, alla funzione di confronto e così via.

### Utilizzo

L'utilizzo è davvero semplice: basta passare una variabile di tipo any alla funzione `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)

	// Confronta i due valori utilizzando la funzione Equal dalle informazioni sul tipo
	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))
}
```

Nell'esempio precedente, i valori interi e in virgola mobile vengono passati alla funzione `GetTypeInfo`, di cui si stampano le rispettive informazioni sul tipo; quindi la funzione `Equal` viene utilizzata per confrontare i valori. In questo modo è possibile ottenere le informazioni sul tipo e confrontare i tipi in modo più rapido.

Inoltre, questo metodo può essere applicato in modo analogo a strutture, puntatori, interfacce e così via, e consente anche di risolvere il problema del typed nil, un inconveniente piuttosto frequente. `Hash` viene comunque valorizzato quando il tipo è presente, mentre `This` vale 0 se è nil.

## Conclusione

EFace svolge un ruolo importante nella gestione del tipo any nel linguaggio Go attuale. Grazie ad esso, è possibile trattare valori di tipi diversi in modo flessibile e rapido, nonché ottenere e sfruttare informazioni dettagliate sui tipi. Tuttavia, si tratta di una funzionalità nascosta all'interno del runtime, che potrebbe essere influenzata dalle modifiche alla specifica del linguaggio; è quindi necessario procedere con cautela.
