---
id: 548504c5a0b4857763527603f3e1059e
author: snowmerak
title: Any není Any, ale Any je Any
description: Podrobně analyzujeme typ `any` jazyka Go a jeho interní strukturu `EFace` a vysvětlujeme metody dynamického zpracování typů pomocí balíčku `reflect` a type assertion a type switch.
language: cs
date: 2025-09-30T15:12:53.689280321Z
path: /blog/posts/any-is-not-any-but-any-is-any-z6161856d
category: language
---

## Any

V jazyce Go je typ any aliasem pro `interface{}`, kouzelné rozhraní, které dokáže uchovat hodnoty libovolného typu. Jinými slovy, do proměnné typu any lze přiřadit hodnotu jakéhokoli typu.

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

Takto typ any umožňuje uchovávat hodnoty různých typů, což umožňuje psát flexibilní kód. Při používání typu any je však třeba dbát na několik věcí.

### Type Assertion

Chcete-li použít skutečnou hodnotu v proměnné typu any, je nutné použít typovou assertion (type assertion). Typová assertion slouží k tomu, aby sdělila kompilátoru, že proměnná typu any má konkrétní typ.

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

Ve výše uvedeném příkladu `a.(string)` tvrdí, že `a` je typu string. Pokud `a` není typu string, `ok` má hodnotu false a lze tak zabránit tomu, aby program zpanikařil.

### Type Switch

Přepínač typů (type switch) umožňuje provádět různé operace podle skutečného typu proměnné typu any. Je užitečný, když je potřeba zpracovat více typů.

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

Ve výše uvedeném příkladu `a.(type)` kontroluje skutečný typ `a` a provede větev odpovídající tomuto typu.

### Reflection

Balíček reflect v jazyce Go umožňuje dynamicky zkoumat a upravovat typ a hodnotu proměnné typu any za běhu programu. Je užitečný při práci se složitými datovými strukturami.

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

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

Ve výše uvedeném příkladu lze pomocí balíčku reflect ověřit typ a hodnotu `a` za běhu programu.

## EFace

V jazyce Go se rozhraní dělí na dvě hlavní formy: EFace (Empty Interface) a IFace (Interface with Methods). Z nich EFace odpovídá pojmu typu any, kterým jsme se zabývali dosud.

### Struktura

EFace je speciální struktura existující pouze uvnitř běhového prostředí (runtime) jazyka Go, proto ji zde budeme zpracovávat pomocí napodobeniny (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 má dvě pole:

- `Type`: ukazatel obsahující metadata o skutečném typu hodnoty.
- `Data`: ukazatel obsahující skutečnou hodnotu.

EFace interně spravuje informace o typu prostřednictvím struktury `runtimeType`. Tato struktura obsahuje různá metadata, například velikost typu, zarovnání a hodnotu hash.

Na co bychom se v této struktuře měli zaměřit, jsou pole `Kind_`, `Hash` a `Equal`. `Kind_` označuje druh typu, zatímco `Hash` a `Equal` se používají k výpočtu hodnoty hash a k porovnání typů v hash tabulkách.

### Obalení

Nyní tento EFace obalíme, abychom s ním mohli pohodlněji pracovat a provádět černou magii.

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

Výše uvedená funkce přijme proměnnou typu any, extrahuje z ní interní strukturu EFace, získá z ní informace o typu a vrátí je jako strukturu `TypeInfo`. Pomocí `TypeInfo` nyní snadno přistoupíme k hodnotě hash typu, jeho druhu, porovnávací funkci a dalším údajům.

### Použití

Použití je opravdu jednoduché. Stačí předat proměnnou typu any funkci `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))
}
```

Ve výše uvedeném příkladu předáváme celočíselnou hodnotu a hodnotu s plovoucí desetinnou čárkou funkci `GetTypeInfo`, vypisujeme jejich informace o typu a pomocí funkce `Equal` porovnáváme hodnoty. Díky tomu lze rychleji získat informace o typu a typy porovnávat.

Tento způsob lze také použít u struktur, ukazatelů, rozhraní a podobně a lze jím řešit i běžně se vyskytující problém typed nil. `Hash` bude přiřazen, pokud typ existuje, zatímco `This` bude nulové (0), pokud je hodnota nil.

## Závěr

EFace hraje v současném Go důležitou roli při práci s typem any. Umožňuje zpracovávat hodnoty různých typů flexibilně a rychle a získávat podrobné informace o typu a využívat je. Je však třeba mít na paměti, že jde o funkcionalitu skrytou uvnitř běhového prostředí, a proto může být ovlivněna změnami jazykové specifikace.
