---
id: 548504c5a0b4857763527603f3e1059e
author: snowmerak
title: Any は Any ではないが、Any は Any である
description: Go言語の`any`型と内部の`EFace`構造を詳細に分析し、`reflect`パッケージおよび型アサーション・型スイッチを活用した動的型処理の方法について説明します。
language: ja
date: 2025-09-30T15:12:53.689280321Z
path: /blog/posts/any-is-not-any-but-any-is-any-z6161856d
category: language
---

## Any

Go言語において any 型は、あらゆる型の値を格納できる魔法のようなインターフェース、`interface{}` の別名です。つまり、どのような型であっても any 型の変数に代入することができます。

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

このように any 型は多様な型の値を格納できるため、柔軟なコードを記述することを可能にします。しかしながら、any 型を使用する際にはいくつかの注意点があります。

### Type Assertion

any 型の変数から実際の値を利用するには、型アサーション(type assertion)を使用しなければなりません。型アサーションは、any 型の変数が特定の型であることをコンパイラに伝える役割を果たします。

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

上記の例において、`a.(string)` は `a` が string 型であることをアサーションします。もし `a` が string 型でなければ、`ok` は false となり、プログラムがパニックに陥ることを防ぐことができます。

### Type Switch

型スイッチ(type switch)は、any 型の変数の実際の型に応じて異なる処理を実行できるようにします。これは複数の型を扱う必要がある場合に有用です。

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

上記の例において、`a.(type)` は `a` の実際の型を検査し、該当する型のケースを実行します。

### Reflection

Go言語の reflect パッケージを使用すると、any 型の変数の型と値を実行時に動的に検査および操作することができます。これは複雑なデータ構造を扱う際に有用です。

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

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

上記の例において、reflect パッケージを使用することで、`a` の型と値を実行時に確認することができます。

## EFace

Go言語におけるインターフェースは、二つの主要な形態に分けられます: EFace(Empty Interface)と IFace(Interface with Methods)です。このうち EFace が、これまで取り扱ってきた any 型と同一の概念です。

### 構造

EFace は Go言語のランタイム内にのみ存在する特殊な構造体であるため、ここではミミック(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 は二つのフィールドを持っています:

- `Type`: 値の実際の型に関するメタデータを保持するポインタです。
- `Data`: 実際の値を保持するポインタです。

さらに EFace は内部的に `runtimeType` 構造体を通じて型情報を管理します。この構造体は、型のサイズ、アラインメント、ハッシュ値など、多様なメタデータを含んでいます。

この中で注目すべき部分は `Kind_`、`Hash`、`Equal` フィールドです。`Kind_` は型の種類を示し、`Hash` と `Equal` はハッシュテーブルにおいて型を比較し、ハッシュ値を計算するために使用されます。

### ラッピング

では、この EFace をラップして、より簡単に黒魔術を使えるようにしてみましょう。

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

上記の関数は any 型の変数を受け取り、内部の EFace 構造体を抽出して、そこから型情報を取り出し `TypeInfo` 構造体として返します。これにより、`TypeInfo` を用いて型のハッシュ値、種類、比較関数などに容易にアクセスできるようになります。

### 活用

活用は非常に簡単です。`GetTypeInfo` 関数に any 型の変数を渡すだけです。

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

上記の例では、整数と浮動小数点数の値を `GetTypeInfo` 関数に渡して、それぞれの型情報を出力し、`Equal` 関数を用いて値を比較しています。これにより、より迅速に型情報を取得し、型を比較することができます。

また、この方法は構造体、ポインタ、インターフェースなどにも同様に適用でき、少なからず発生する問題である型付き nil(typed nil) の問題も解決することができます。`Hash` は型が存在すれば必ず値が設定されていますが、`This` は nil の場合 0 となるためです。

## 結論

EFace は現在の Go言語において any 型を扱ううえで重要な役割を果たしています。これにより、多様な型の値を柔軟かつ迅速に処理することができ、型情報を詳細に取得して活用することが可能です。ただし、これはランタイム内部に隠された機能であり、言語仕様の変更の影響を受ける可能性があるため、注意が必要です。
