---
id: 548504c5a0b4857763527603f3e1059e
author: snowmerak
title: Any är inte Any, men Any är Any
description: Denna text analyserar i detalj Go-språkets `any`-typ och dess interna `EFace`-struktur, samt förklarar hur dynamisk typhantering kan genomföras med hjälp av paketet `reflect` och typassertioner/typswitchar.
language: sv
date: 2025-09-30T15:12:53.689280321Z
path: /blog/posts/any-is-not-any-but-any-is-any-z6161856d
category: language
---

## Any

I Go-språket är any-typen ett alias för `interface{}`, ett magiskt gränssnitt som kan innehålla vilken typ som helst. Det innebär att vilken typ som helst kan tilldelas en variabel av typen any.

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

Således gör any-typen det möjligt att skriva flexibel kod, eftersom den kan innehålla värden av många olika typer. Vid användning av any-typen finns dock några saker att vara uppmärksam på.

### Type Assertion

För att använda det faktiska värdet i en variabel av typen any måste man använda typpåstående (type assertion). Typpåstående informerar kompilatorn om att variabeln av typen any har en viss specifik typ.

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

I exemplet ovan påstår `a.(string)` att `a` är av typen string. Om `a` inte är av typen string blir `ok` false, vilket förhindrar att programmet går i panik.

### Type Switch

Typväxling (type switch) gör det möjligt att utföra olika åtgärder beroende på den faktiska typen hos en variabel av typen any. Detta är användbart när flera typer måste hanteras.

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

I exemplet ovan kontrollerar `a.(type)` den faktiska typen av `a` och kör därefter det case som motsvarar den typen.

### Reflection

Med hjälp av paketet reflect i Go-språket kan man dynamiskt undersöka och manipulera typen och värdet hos en variabel av typen any under körning. Detta är användbart när komplexa datastrukturer hanteras.

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

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

I exemplet ovan använder vi paketet reflect för att under körning kontrollera typen och värdet hos `a`.

## EFace

I Go-språket delas gränssnitt upp i två huvudsakliga former: EFace (Empty Interface) och IFace (Interface with Methods). Bland dessa är EFace detsamma som det any-typen vi har behandlat hittills.

### Struktur

EFace är en särskild struktur som endast existerar inom Go-språkets runtime, därför kommer vi här att skapa en mimic för att arbeta med den.

```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 har två fält:

- `Type`: en pekare som innehåller metadata om värdets faktiska typ.
- `Data`: en pekare som innehåller det faktiska värdet.

Dessutom hanterar EFace typinformation internt genom strukturen `runtimeType`. Denna struktur innehåller olika metadata, såsom typens storlek, justering och hashvärde.

Det som vi bör uppmärksamma i detta är fälten `Kind_`, `Hash` och `Equal`. `Kind_` anger typens slag, medan `Hash` och `Equal` används för att jämföra typer och beräkna hashvärden i hashtabeller.

### Inslagning

Låt oss nu slå in denna EFace i ett omslag så att vi kan använda den svarta magin bekvämare.

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

Funktionen ovan tar emot en variabel av typen any, extraherar den interna EFace-strukturen, hämtar typinformationen och returnerar den som en struktur `TypeInfo`. Nu kan vi enkelt komma åt typens hashvärde, slag, jämförelsefunktion med mera genom denna `TypeInfo`.

### Användning

Användningen är verkligen enkel. Man behöver bara skicka en variabel av typen any till funktionen `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)

	// Jämför de två värdena med Equal-funktionen från typinformationen
	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))
}
```

I exemplet ovan skickar vi ett heltal och ett flyttal till funktionen `GetTypeInfo`, skriver ut respektive typinformation och jämför värdena med funktionen `Equal`. På så sätt kan vi snabbare få typinformation och jämföra typer.

Denna metod kan dessutom användas på samma sätt för strukturer, pekare, gränssnitt och liknande, och den kan även lösa det vanligt förekommande problemet med typed nil. `Hash` har ett tilldelat värde så länge typen finns, medan `This` är 0 om värdet är nil.

## Slutsats

EFace spelar en viktig roll för hanteringen av any-typen i Go-språket i dagsläget. Genom den kan man hantera värden av många olika typer på ett flexibelt och effektivt sätt samt erhålla och använda detaljerad typinformation. Det bör dock beaktas att detta är en funktion som är dold inom runtime och därför kan påverkas av förändringar i språkspecifikationen.
