[Golang] reflectパッケージの使い方を調べたら書く

# はじめに
最近reflectパッケージを使う機会があったので、その時どう書けばいいか調べたことをメモ書き。
気が向いたら更新してく。
面倒なのでimportとかは端折る。

# reflect パッケージ
なにものなのかは [godoc](https://pkg.go.dev/reflect) を見る。
[DeepL翻訳](https://www.deepl.com/ja/translator)様様で翻訳した内容↓

> reflectパッケージは、プログラムが任意の型を持つオブジェクトを操作することを可能にする、ランタイムリフレクションを実装しています。典型的な使い方は，静的な型interface{}を持つ値を受け取り， TypeOfを呼んで動的な型情報を取り出し，それをTypeで返すというものです．
>
> ValueOfを呼び出すと、実行時データを表すValueが返される。ZeroはTypeを取り、その型に対するゼロ値を表すValueを返す。


godocにも書かれているが [https://go.dev/blog/laws-of-reflection](https://go.dev/blog/laws-of-reflection) も見てみると良さそう。

# いろいろ使い方

## Type/Valueを取得

`interface{}`を扱う場合の基本はここから始まる。

```go
func a(v interface{}) {
	rt := reflect.TypeOf(v)  // return reflect.Type
	rv := reflect.ValueOf(v) // return reflect.Value
	// do something...
}
```

### 型を判定して分岐処理をする

`reflect`パッケージで定数化されている型はGitHubの [reflect/type.go](https://github.com/golang/go/blob/master/src/reflect/type.go#L239-L269) を参照。

```go
func a(rt reflect.Type) {
	switch rt.Kind() {
	case reflect.String:
		// string型の場合の処理
	case reflect.Struct:
		// 構造体の場合の処理
	case reflect.Ptr:
		// ポインタの場合の処理
	default:
		// いずれの型でもない
	}
}
```

`reflect.Value`でも同様に`Kind()`を呼び出すことで型判定が可能。
（値がポインタでなければ基本的には問題なと思う。たぶん。）

```go
func a(rv reflect.Kind) {
	switch rv.Kind() {
	case reflect.String:
		// string型の場合の処理
	default:
		// いずれの型でもない
	}
}
```

### 型を判定して分岐処理をする（ポインタを考慮）

`reflect.Type`の`Elem()`を実行すれば良い。

※`Array`, `Chan`, `Map`, `Ptr`, `Slice`以外の型に対して`Elem()`を呼び出すとpanicが発生する。

```go
func a(rt reflect.Type) {
	switch rt.Kind() {
	case reflect.String:
		fmt.Println("string")
	case reflect.Ptr:
		fmt.Println("pointer")
		a(rt.Elem())
	default:
		fmt.Printf("other(%s)", rt.Kind())
	}
}
```

`reflect.Value`でも同様の処理を書くことは可能だがnil値の考慮が必要になる。

これはNGな例

```go
func main() {
	var s *string
	a(reflect.ValueOf(s))
}

func a(rv reflect.Value) {
	switch rv.Kind() {
	case reflect.String:
		fmt.Println("string")
	case reflect.Ptr:
		fmt.Println("pointer")
		a(rv.Elem())
	default:
		fmt.Printf("other(%s)", rv.Kind())
	}
}
```

このコードを実行すると出力は以下のようになる。
nil値のポインタ型に対して`Elem()`を実行した場合、`Kind()`メソッドが返す値は`reflect.Invalid`になるので、おそらく書いた本人が意図した挙動にはならない。

```
$ go run main.go
pointer!!
other(invalid)
```

`reflect.Ptr`の場合に`IsNil()`を呼び出すことでnil値か判定してあげれば同じようなことができないわけではない。

```go
func a(rv reflect.Value) {
	switch rv.Kind() {
	case reflect.String:
		fmt.Println("string")
	case reflect.Ptr:
		fmt.Println("pointer")
		if rv.IsNil() {
			fmt.Println("nil!!")
			return
		}
		a(rv.Elem())
	default:
		fmt.Printf("other(%s)", rv.Kind())
	}
}
```

## Array, Sliceの型を取得

例えばSliceに設定可能な型を取得したい場合、`Elem().Kind()`で取得できる。

```go
var s []string

rt := reflect.TypeOf(s)
fmt.Println(rt.Elem().Kind()) // string

rv := reflect.ValueOf(s)
fmt.Println(rv.Type().Elem().Kind()) // string
```

## reflect.Valueから値を取り出す

### プリミティブ型

取得したい型に対応するメソッドが用意されているので実行すれば良い。

※`String()`以外のメソッドは実際の値の型と異なるメソッドを呼び出すとpanicが発生する。

```go
func a(rv reflect.Value) {
	switch rv.Kind() {
	case reflect.Bool:
		fmt.Println(rv.Bool())
	case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
		fmt.Println(rv.Int())
	case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
		fmt.Println(rv.Uint())
	case reflect.Float32, reflect.Float64:
		fmt.Println(rv.Float())
	case reflect.String:
		fmt.Println(rv.String())
	default:
		fmt.Printf("other(%s)", rv.Kind())
	}
}
```

`String()`はpanicを発生させることはないが、値がstring以外の型の場合は `<int Value>` のような文字列が返ってくる。
設定された値を文字列として出力したい場合に`String()`を使用すると意図しない結果になるので注意が必要。

それぞれの型でstringに変換するような処理を実装してあげる。

```go
func a(rv reflect.Value) {
	switch rv.Kind() {
	case reflect.Bool:
		if rv.Bool() {
			fmt.Println("true")	
		} else {
			fmt.Println("false")	
		}
	case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
		fmt.Println(strconv.FormatInt(rv.Int(), 10))
	case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
		fmt.Println(strconv.FormatUint(rv.Uint(), 10))
	case reflect.Float32:
		fmt.Println(strconv.FormatFloat(rv.Float(), 'f', -1, 32))
	case reflect.Float64:
		fmt.Println(strconv.FormatFloat(rv.Float(), 'f', -1, 64))
	case reflect.String:
		fmt.Println(rv.String())
	default:
		fmt.Printf("other(%s)", rv.Kind())
	}
}
```

ただ文字列になればいいだけなら別にこれでも良いが。

```go
func a(rv reflect.Value) {
	fmt.Printf("%v", rv.Interface())
}
```

### Array、Slice

SliceとArrayの使い方は基本的に同じ。
`Len()`を呼び出すと長さが取得できるのでforで回しながら`Index()`を呼び出して値を取得していく。
`Index()`は`reflect.Value`を返すので、型によって処理分岐したければ`Kind()`を使う。

ちなみに`Cap()`を呼び出すとcapacityを取得できる。

※`Len()`と`Cap()`は`Array`, `Chan`, `Slice`型以外の場合panicが発生する。
※`Index()`は`Array`, `Slice`, `String`型以外の場合panicが発生する。

```go
func a(rv reflect.Value) {
	fmt.Println(rv.Len())
	fmt.Println(rv.Cap())

	for i := 0; i < rv.Len(); i++ {
		fmt.Println(rv.Index(i).String())
	}
}
```

### Map

`MapRange()`を呼び出して、要素がなくなるまでforで回していく。
Mapのキーと値はそれぞれ`reflect.MapIter`の`Key()`, `Value()`で取得可能。
KeyとValuえはともに`reflect.Value`を返すので、型によって処理分岐したければ`Kind()`を使う。

※`MapRange()`は`Map`型以外の場合panicが発生する。

```go
func a(rv reflect.Value) {
	iter := rv.MapRange() // return *reflect.MapIter
	for iter.Next() {
		fmt.Printf("key: %v, value: %v", iter.Key(), iter.Value())
	}
}
```

### 構造体

`NumField()`で構造体が持つフィールド数を取得し、forで回していく。
フィールドの情報を取得するには`Type()`で一度`reflect.Type`を取得してから、`Field()`を実行する必要がある。
フィールドの値を取得するには`FieldByName()`を使用する(戻り値は`reflect.Value`)

※`NumField()`, `Field()` `FieldByName()`は`Struct`型以外の場合panicが発生する。

```go
func a(rv reflect.Value) {
	for i := 0; i < rv.NumField(); i++ {
		f := rv.Type().Field(i)
		fv := rv.FieldByName(f.Name)
		fmt.Printf("field name: %s, value: %v", f.Name, fv)
	}
}
```

#### その他構造体のフィールドから情報を取るメソッド

##### タグを取得

`Tag`フィールドの`Get()`を実行する。
タグは文字列で帰ってくるので、あとは自分が使いたいようにパースしたりして使う。

[encoding/json](https://github.com/golang/go/blob/master/src/encoding/json/tags.go) の実装を参考にしてみると良いかも。

```go
func main() {
	a(reflect.ValueOf(struct {
		a string `json:"abcde"`
	}{a: "aaaa"})) // tag: "abcde"
	a(reflect.ValueOf(struct{ a string }{a: "aaaa"})) // tag: ""
}

func a(rv reflect.Value) {
	for i := 0; i < rv.NumField(); i++ {
		f := rv.Type().Field(i)
		fmt.Printf("field name: %s, tag: %v\n", f.Name, f.Tag.Get("json"))
	}
}
```

##### フィールドがPublicかPrivateか判定

`IsExported()`を使う

[encoding/json](https://github.com/golang/go/blob/master/src/encoding/json/encode.go#L1244-L1258) でも使っている。

```go
func main() {
	a(reflect.ValueOf(struct{ A string }{A: "aaaa"})) // exported: true
	a(reflect.ValueOf(struct{ a string }{a: "aaaa"})) // exported: false
}

func a(rv reflect.Value) {
	for i := 0; i < rv.NumField(); i++ {
		f := rv.Type().Field(i)
		fmt.Printf("field name: %s, exported: %v", f.Name, f.IsExported())
	}
}
```

### interface{}

`interface{}`を返すやつ
（TODO: 使ってないので雑）

```go
func a(rv reflect.Value) {
	fmt.Println(rv.Interface())
}
```

## reflect.Valueに値を設定する

reflectを使用して元の値を書き換えるためには [https://go.dev/blog/laws-of-reflection](https://go.dev/blog/laws-of-reflection) の`第3法則` で説明されている内容が大事なポイント。

> 3. To modify a reflection object, the value must be settable.

上記のように書かれています。
[DeepL翻訳](https://www.deepl.com/ja/translator)様様で翻訳した内容↓

> 3. Reflectionオブジェクトを変更するには、その値が設定可能でなければなりません

詳細な内容は [https://go.dev/blog/laws-of-reflection](https://go.dev/blog/laws-of-reflection) を見たほうが良い。

**一応雑に書くとこんな感じ**

以下のコードは`x`のコピーが`reflect.ValueOf`に渡るため
`reflect.ValueOf`の引数として生成されるインターフェース値は`x`そのものではない。

```go
var x float64 = 3.4
v := reflect.ValueOf(x)
```

そのため以下のコードがもし成功したとしても、元の変数`x`の値は変わることはない。
そのような挙動は混乱を招き、役に立たないため違反であるため、panicが発生する。

```go
v.SetFloat(7.1)
```

値が設定可能であるかを判定するには `CanSet()` メソッドを使用すれば良い。

```go
var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println(v.CanSet()) // false
```

値が設定可能であるとするためには、`ValueOf()`に変数`x`のポインタを渡す必要がある。

```go
var x float64 = 3.4
v := reflect.ValueOf(&x) // --> set pointer
fmt.Println(v.CanSet()) // false
```

さらにポインタの参照先のValueを取得するために`Elem()`を使用することで、値が設定可能になります。

```go
var x float64 = 3.4
v := reflect.ValueOf(&x)
fmt.Println(v.Elem().CanSet()) // true
```

---

### Set

型を意識せずに値を設定したいだけなら`Set()`を呼び出せば良い。

```go
func a(rv reflect.Value, v interface{}) {
	src := reflect.ValueOf(v)
	rv.Elem().Set(src)
}
```

### SetXXX

`Set()`ではなく、型に対応したメソッドを使うという方法もある。
設定したい型に対応するメソッドが用意されているので実行すれば良い。

```go
func a(dist reflect.Value, v interface{}) {
	rv := reflect.ValueOf(v)

	switch rv.Kind() {
	case reflect.Bool:
		dist.SetBool(rv.Bool())
	case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
		dist.SetInt(rv.Int())
	case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
		dist.SetUint(rv.Uint())
	case reflect.Float32, reflect.Float64:
		dist.SetFloat(rv.Float())
	case reflect.String:
		dist.SetString(rv.String())
	default:
		fmt.Printf("other(%s)", rv.Kind())
	}
}
```

### Arrayの各indexに値を設定

`Index().Set()`を使う。

当然だが`len(dist)` < `len(src)`の場合はpanic(`reflect: array index out of range`)が発生するので
ちゃんとやるなら双方の`Len()`のチェックを行うべきである。

```go
func main() {
	var s [3]string
	rv := reflect.ValueOf(&s)

	fmt.Println(s) // ["", "", ""]
	a(rv, []string{"a", "b"})
	fmt.Println(s) // ["a", "b", ""]
}

func a(rv reflect.Value, src []string) {
	dist := rv.Elem()

	for i, s := range src {
		dist.Index(i).Set(reflect.ValueOf(s))
	}
}
```

### Sliceに値を追加

`reflect.AppendSlice()`を使用し、戻り値を`Set()`に渡す。

`reflect.AppendSlice()`はSlice同士の結合を行うため、第2引数にはSliceを`reflect.ValueOf()`した結果を渡す必要がある。

```go
func main() {
	var s []string
	rv := reflect.ValueOf(&s)

	fmt.Println(s) // []
	a(rv, []string{"a", "b", "c"})
	fmt.Println(s) // ["a", "b", "c"]
	a(rv, []string{"1", "2", "3"})
	fmt.Println(s) // ["a", "b", "c", "1", "2", "3"]
}

func a(rv reflect.Value, src []string) {
	dist := rv.Elem()
	dist.Set(reflect.AppendSlice(dist, reflect.ValueOf(src)))
}
```

### Mapのキーを指定して値を設定

`SetMapIndex()`にキーと値のValueを設定する。

```go
func main() {
	s := map[string]string{}
	rv := reflect.ValueOf(&s)

	fmt.Println(s) // map[]
	a(rv, map[string]string{"a": "hoge", "b": "fuga"})
	fmt.Println(s) // map[a:hoge b:fuga]
	a(rv, map[string]string{"b": "mage", "c": "age"})
	fmt.Println(s) // map[a:hoge b:mage c:age]
}

func a(rv reflect.Value, src map[string]string) {
	dist := rv.Elem()

	for key, val := range src {
		dist.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(val))
	}
}
```

## 値を初期化する

### Arrayを作る

`reflect.ArrayOf()`を使う。
例えば`[5]string`を作りたい場合は以下のようになる。

`reflect.New()`は`reflect.Ptr`型の`reflect.Value`を返すので、`Elem()`を使用しする必要がある。

```go
rv := reflect.New(reflect.ArrayOf(5, reflect.TypeOf("")))
fmt.Printf("%#v\n", rv)        // &[5]string{"", "", "", "", ""}
fmt.Printf("%#v\n", rv.Elem()) // [5]string{"", "", "", "", ""}
```

### Sliceを作る

`reflect.MakeSlice()`を使う。
`make()`と同様にlen, capを指定して使う。

```go
s := []string{}

rv := reflect.MakeSlice(reflect.TypeOf(s), 5, 10)
fmt.Printf("%#v\n", rv)           // []string{"", "", "", "", ""}
fmt.Printf("len: %d\n", rv.Len()) // len: 5
fmt.Printf("cap: %d\n", rv.Cap()) // cap: 10
}
```

### Mapを作る

`reflect.MakeMap`を使う。

```go
s := map[string]string{}

rv := reflect.MakeMap(reflect.TypeOf(s))
fmt.Printf("%#v\n", rv)           // map[string]string{}
```

### 構造体を作る

`reflect.New()`に構造体のTypeを渡す。

```go
s := struct {
	A string
	B int
}{}

rv := reflect.New(reflect.TypeOf(s))
fmt.Printf("%#v\n", rv)        // &struct { A string; B int }{A:"", B:0}
fmt.Printf("%#v\n", rv.Elem()) // struct { A string; B int }{A:"", B:0}
}
```