---
id: 548504c5a0b4857763527603f3e1059e
author: snowmerak
title: Any ist nicht Any, aber Any ist Any
description: Dieser Text analysiert detailliert den Typ `any` der Sprache Go sowie dessen interne Struktur `EFace` und erläutert Methoden zur dynamischen Typverarbeitung unter Verwendung des Pakets `reflect` sowie von Typassertionen und Typ-Switches.
language: de
date: 2025-09-30T15:12:53.689280321Z
path: /blog/posts/any-is-not-any-but-any-is-any-z6161856d
category: language
---

## Any

In der Programmiersprache Go ist der Typ any ein Alias für `interface{}`, eine magisch anmutende Schnittstelle, die Werte beliebiger Typen aufnehmen kann. Anders ausgedrückt kann jeder Typ einer Variablen vom Typ any zugewiesen werden.

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

Auf diese Weise ermöglicht der Typ any, Werte verschiedener Typen aufzunehmen, und erlaubt so das Schreiben flexibler Code. Bei der Verwendung des Typs any sind jedoch einige Punkte zu beachten.

### Type Assertion

Um den tatsächlichen Wert einer Variablen vom Typ any zu verwenden, muss eine Typzusicherung (type assertion) eingesetzt werden. Die Typzusicherung teilt dem Compiler mit, dass die Variable vom Typ any einen bestimmten Typ besitzt.

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

In dem obigen Beispiel behauptet `a.(string)`, dass `a` den Typ string besitzt. Falls `a` nicht vom Typ string ist, wird `ok` zu false, und ein Absturz des Programms in Form einer Panik kann auf diese Weise verhindert werden.

### Type Switch

Der Type Switch (type switch) ermöglicht es, je nach dem tatsächlichen Typ einer Variablen vom Typ any unterschiedliche Operationen auszuführen. Dies ist nützlich, wenn mehrere Typen verarbeitet werden müssen.

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

In dem obigen Beispiel prüft `a.(type)` den tatsächlichen Typ von `a` und führt den zu diesem Typ passenden Fall aus.

### Reflection

Mit dem Paket reflect der Sprache Go lassen sich Typ und Wert einer Variablen vom Typ any zur Laufzeit dynamisch untersuchen und manipulieren. Dies ist beim Umgang mit komplexen Datenstrukturen nützlich.

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

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

In dem obigen Beispiel werden mithilfe des Pakets reflect Typ und Wert von `a` zur Laufzeit ermittelt.

## EFace

In der Sprache Go teilen sich Schnittstellen in zwei Hauptformen auf: EFace (Empty Interface) und IFace (Interface with Methods). Davon entspricht EFace dem Konzept des Typs any, das wir bisher behandelt haben.

### Struktur

Da EFace eine besondere Struktur ist, die nur innerhalb der Laufzeit von Go existiert, werden wir hier ein Mimic (mimic) erstellen und damit arbeiten.

```go
type runtimeTypeMimic struct {
	Size_       uintptr
	PtrBytes    uintptr // Anzahl der (Präfix-)Bytes im Typ, die Zeiger enthalten können
	Hash        uint32  // Hashwert des Typs; vermeidet Berechnungen in Hashtabellen
	TFlag       uint8   // zusätzliche Flags mit Typinformationen
	Align_      uint8   // Ausrichtung einer Variablen dieses Typs
	FieldAlign_ uint8   // Ausrichtung eines Struktur-Feldes dieses Typs
	Kind_       uint8   // Aufzählung für C
	Equal       func(unsafe.Pointer, unsafe.Pointer) bool
	GCData      *byte
	Str         int32 // String-Form
	PtrToThis   int32 // Typ für einen Zeiger auf diesen Typ, kann null sein
}

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

EFace besitzt zwei Felder:

- `Type`: Ein Zeiger, der die Metadaten zum tatsächlichen Typ des Wertes enthält.
- `Data`: Ein Zeiger, der den tatsächlichen Wert enthält.

Außerdem verwaltet EFace die Typinformationen intern über die Struktur `runtimeType`. Diese Struktur enthält verschiedene Metadaten wie die Größe des Typs, seine Ausrichtung, seinen Hashwert usw.

Darin sind vor allem die Felder `Kind_`, `Hash` und `Equal` von Bedeutung. `Kind_` gibt die Art des Typs an, während `Hash` und `Equal` in Hashtabellen zum Vergleichen von Typen und zur Berechnung von Hashwerten verwendet werden.

### Kapselung

Lassen Sie uns nun dieses EFace kapseln, damit sich diese Low-Level-Techniken bequemer nutzen lassen.

```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,
	}
}
```

Die obige Funktion nimmt eine Variable vom Typ any entgegen, extrahiert daraus die interne Struktur EFace, entnimmt die Typinformationen und gibt sie als Struktur `TypeInfo` zurück. Mithilfe von `TypeInfo` lassen sich nun Hashwert, Art, Vergleichsfunktion usw. des Typs einfach abrufen.

### Verwendung

Die Verwendung ist wirklich einfach. Man übergibt einfach eine Variable vom Typ any an die Funktion `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)

	// Die beiden Werte mithilfe der Equal-Funktion aus den Typinformationen vergleichen
	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))
}
```

In dem obigen Beispiel werden ganzzahlige und Gleitkommawerte an die Funktion `GetTypeInfo` übergeben, deren Typinformationen ausgegeben und mithilfe der Funktion `Equal` verglichen. Auf diese Weise lassen sich Typinformationen schneller ermitteln und Typen vergleichen.

Darüber hinaus lässt sich diese Methode gleichermaßen auf Strukturen, Zeiger, Schnittstellen usw. anwenden, und sie kann auch das nicht seltene Problem des typed nil (typed nil) lösen. Denn `Hash` ist bei vorhandenem Typ zugewiesen, während `This` bei nil den Wert 0 besitzt.

## Fazit

EFace spielt in der aktuellen Sprache Go eine wichtige Rolle bei der Handhabung des Typs any. Auf diese Weise lassen sich Werte verschiedener Typen flexibel und schnell verarbeiten sowie Typinformationen detailliert abrufen und nutzen. Allerdings handelt es sich dabei um eine innerhalb der Laufzeit verborgene Funktionalität, die von Änderungen der Sprachspezifikation betroffen sein kann; daher ist Vorsicht geboten.
