---
id: 548504c5a0b4857763527603f3e1059e
author: snowmerak
title: Any nie je Any, ale Any je Any
description: Podrobne analyzujeme typ `any` jazyka Go a jeho internú štruktúru `EFace`, a vysvetľujeme metódy spracovania dynamických typov pomocou balíka `reflect` a type assertions a type switchov.
language: sk
date: 2025-09-30T15:12:53.689280321Z
path: /blog/posts/any-is-not-any-but-any-is-any-z6161856d
category: language
---

## Any

V jazyku Go je typ any alias pre `interface{}`, čarovné rozhranie, ktoré dokáže uchovať hodnoty akéhokoľvek typu. Inými slovami, do premennej typu any možno priradiť hodnotu ľubovoľného typu.

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

Takto typ any umožňuje uchovávať hodnoty rôznych typov, čo umožňuje písať flexibilný kód. Pri používaní typu any však treba dbať na niekoľko vecí.

### Type Assertion

Ak chcete použiť skutočnú hodnotu v premennej typu any, musíte použiť type assertion (typovú aserciu). Typová aserícia slúži na to, aby sa kompilátoru oznámilo, že premenná typu any má konkrétny typ.

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

V uvedenom príklade `a.(string)` tvrdí, že `a` je typu string. Ak `a` nie je typu string, `ok` bude false a zabráni sa tomu, aby program upadol do panicu.

### Type Switch

Type switch (prepínač typov) umožňuje vykonávať rôzne operácie podľa skutočného typu premennej typu any. Je užitočný vtedy, keď treba spracovať viacero typov.

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

V uvedenom príklade `a.(type)` kontroluje skutočný typ `a` a vykoná prípad zodpovedajúci tomuto typu.

### Reflection

Balík reflect v jazyku Go umožňuje dynamicky za behu kontrolovať a manipulovať s typom a hodnotou premennej typu any. Je užitočný pri práci so zložitými dátovými štruktúrami.

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

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

V uvedenom príklade môžeme pomocou balíka reflect za behu zistiť typ a hodnotu `a`.

## EFace

V jazyku Go sa rozhrania delia na dva hlavné druhy: EFace (Empty Interface) a IFace (Interface with Methods). Z nich EFace zodpovedá pojmu typu any, ktorým sme sa zaoberali doteraz.

### Štruktúra

EFace je špeciálna štruktúra, ktorá existuje iba vnútri runtime jazyka Go, preto ju tu budeme spracovávať prostredníctvom mimika (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á dve polia:

- `Type`: ukazovateľ na metadáta obsahujúce informácie o skutočnom type hodnoty.
- `Data`: ukazovateľ na samotnú hodnotu.

EFace interne spravuje informácie o type prostredníctvom štruktúry `runtimeType`. Táto štruktúra obsahuje rôzne metadáta, napríklad veľkosť typu, zarovnanie a hodnotu hash.

Na čo by sme sa v nej mali zamerať, sú polia `Kind_`, `Hash` a `Equal`. `Kind_` označuje druh typu, zatiaľ čo `Hash` a `Equal` sa používajú na výpočet hodnoty hash a porovnanie typov v hash tabuľkách.

### Obalenie

Teraz tento EFace obalíme, aby sme s ním mohli pohodlnejšie pracovať s čiernou mágiou.

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

Uvedená funkcia prijme premennú typu any, extrahuje z nej vnútornú štruktúru EFace, získa z nej informácie o type a vráti ich ako štruktúru `TypeInfo`. Teraz môžeme pomocou `TypeInfo` jednoducho pristupovať k hodnote hash typu, jeho druhu, porovnávacej funkcii a ďalším údajom.

### Použitie

Použitie je naozaj jednoduché. Stačí odovzdať premennú typu any funkcii `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))
}
```

V uvedenom príklade odovzdávame celé číslo a číslo s pohyblivou desatinnou čiarkou funkcii `GetTypeInfo`, vypisujeme ich informácie o type a pomocou funkcie `Equal` porovnávame hodnoty. Vďaka tomu môžeme rýchlejšie získať informácie o type a porovnávať typy.

Tento prístup možno rovnako použiť pre štruktúry, ukazovatele, rozhrania a podobne a zároveň rieši častý problém typovaného nil (typed nil). `Hash` má hodnotu priradenú vtedy, keď typ existuje, zatiaľ čo `This` je 0, ak je nil.

## Záver

EFace zohráva v súčasnom jazyku Go dôležitú úlohu pri práci s typom any. Vďaka nemu možno hodnoty rôznych typov spracúvať flexibilne a rýchlo a získavať podrobné informácie o type. Keďže však ide o funkciu skrytú v runtime, môže byť ovplyvnená zmenami jazykovej špecifikácie, preto je potrebná opatrnosť.
