リフレクション - Go

最終更新日: 2026-07-25

TOP(About this memo)) > 一覧(Go) > リフレクション

リフレクション

reflect.ValueOf

var x float64 = 3.4
v := reflect.ValueOf(x) // reflect.Valueを取得
fmt.Println("type:", v.Type())
fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
//type: float64
//kind is float64: true
v := reflect.ValueOf("test")
	fmt.Println(v)          // test
	fmt.Println(v.String()) // test
	//fmt.Println(v.Int())    // panic
	fmt.Println(v.Type())   // string
type myError struct {
	message string
}
func (e *myError) Error() string { // myErrorはerror interfaceを実装している。
	return e.message
}

func main() {
	// 参照型以外に使うとエラーになる。
	//a := 2
	//fmt.Println(reflect.ValueOf(a).IsNil()) // panic

	b := []string{"aaa"}
	fmt.Println(reflect.TypeOf(b))          // []string
	fmt.Println(reflect.ValueOf(b))         // [aaa]
	fmt.Println(reflect.ValueOf(b).IsNil()) // false

	m := map[string]string{}
	fmt.Println(reflect.TypeOf(m))          // map[string]string
	fmt.Println(reflect.ValueOf(m))         // map[]
	fmt.Println(reflect.ValueOf(m).IsNil()) // false

	var p *myError        // myErrorはerrorを実装。
	fmt.Println(p == nil) //true
	var notNilErr error = p
	fmt.Println(notNilErr == nil)                   // false
	fmt.Println(reflect.TypeOf(notNilErr))          // *main.myError
	fmt.Println(reflect.ValueOf(notNilErr))         // <nil>
	fmt.Println(reflect.ValueOf(notNilErr).IsNil()) // true
	fmt.Println(reflect.ValueOf(notNilErr).Elem())  // <invalid reflect.Value>
	//fmt.Println(reflect.ValueOf(notNilErr).Elem().IsNil()) // panic
}
type Value struct {
	typ *rtype
	ptr unsafe.Pointer
	flag
}

reflect.TypeOf

var x float64 = 3.4
fmt.Println("type:", reflect.TypeOf(x))

Interface()

var x float64 = 3.4
v := reflect.ValueOf(x) 
y := v.Interface().(float64) // y will have type float64.
fmt.Println(y)
var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println(v.Interface())
fmt.Println(v)

リフレクトから値を得る手段

fmt.Println(reflect.ValueOf("test").String()) // test
fmt.Println(reflect.ValueOf(time.Now()).Interface().(time.Time))
switch v := rv.Interface().(type) {
	case string:
		if v == "" {
			return false
		}
	case int:
		if v == 0 {
			return false
		}
	case time.Time:
		if v.IsZero() {
			return false
		}
	case *string, *int, *time.Time:
		if v == nil {
			return false
		}
	default:
		panic(fmt.Sprintf("unexpected type: %#v", rv))
	}

Settable

var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("settability of v:", v.CanSet()) // false
v.SetFloat(7.1) // Error: will panic.
var x float64 = 3.4
p := reflect.ValueOf(&x) // Note: take the address of x.
fmt.Println("type of p:", p.Type())
fmt.Println("settability of p:", p.CanSet())               // false
fmt.Println("settability of p.Elem():", p.Elem().CanSet()) // true
p.Elem().SetFloat(7.1)
fmt.Println(p.Interface())        // pointer value
fmt.Println(p.Elem().Interface()) // 7.1
fmt.Println(x)                    // 7.1

reflect.Value.Elem()、reflect.Type.Elem()

k := 3
vk := reflect.ValueOf(k)
fmt.Println(vk.Type()) // int
// Elem()はreflect.Valueの型が参照型じゃない場合はpanicになる。
// fmt.Println(vk.Type().Elem()) // panic
// fmt.Println(vk.Elem()) // panic

// slice型でもエラーになるようだ。
b := []string{"aaa"}
fmt.Println(reflect.TypeOf(b)) // []string
// fmt.Println(reflect.ValueOf(b).Elem()) // panic

var j *int
vj := reflect.ValueOf(j)
// nilであるポインターのValueでも、Type、Type().Elem()はエラーにならない。
fmt.Println(vj.Type()) // *int
fmt.Println(vj.Type().Elem()) // int
// nilであるポインターのValueでも、Elem()はエラーにならないがinvaldが返ってくる。
fmt.Println(vj.Elem())        // <invalid reflect.Value>
// invalidな値に対してType()を実行するとpanicになる。
// fmt.Println(vj.Elem().Type()) // panic

j = &k
vj = reflect.ValueOf(j)
fmt.Println(vj.Type().Elem()) // int
fmt.Println(vj.Elem())        // 3

構造体

type T struct {
    A int
    B string
}
t := T{23, "skidoo"}
s := reflect.ValueOf(&t).Elem()// Elem()で取得したreflect.ValueじゃないとSetができない。
for i := 0; i < s.NumField(); i++ {
    f := s.Field(i) // reflect.Valueを取得
    sf := s.Type().Field(i) // reflect.StructFieldを取得。(※本当はforの外部でs.Type()は取得しておいたほうが効率的)
    fmt.Printf("%d: %s %s = %v\n", i, sf.Name, f.Type(), f.Interface())
}

s.Field(0).SetInt(77)                // &tを渡している、かつElem()で取得しているため、セットできる。
s.Field(1).SetString("Sunset Strip") // &tを渡している、かつElem()で取得しているため、セットできる。
fmt.Println("t is now", t)

var a = 2
b := reflect.ValueOf(a)
s.Field(0).Set(b) // Setでreflect.Valueをセットできる。
fmt.Println("t is now", t)

FieldByName

s := struct{ Name string }{}
vps := reflect.ValueOf(&s).Elem()
vf := vps.FieldByName("Name")
fmt.Println(vf.Type(), vf.CanSet(), vf.CanAddr()) // string true true

New

v := reflect.New(reflect.TypeOf(0))
fmt.Println(v)        // 0x...
fmt.Println(v.Type()) // *int   Newで返されるreflect.Valueの基底はポインターになる。
fmt.Println(v.Elem()) // 0

a := reflect.New(reflect.TypeOf(sql.NullString{}))
fmt.Printf("%v", a) // &{ false}

Indirect

ElemやIndirectで取得したreflect.ValueのTypeが、 reflect.ValueOfとふるまいが違う件

func main() {
	var a any // 型が any。
	a = 4 // 中身はint
	fmt.Println(reflect.ValueOf(a).Type().Kind())         // これは中身の型のintをみる。
	fmt.Println(reflect.ValueOf(&a).Type().Kind())        // ptr
	fmt.Println(reflect.ValueOf(&a).Elem().Type().Kind()) // これは宣言時の型のinterfaceになる。
	fmt.Println(reflect.Indirect(reflect.ValueOf(&a)).Type().Kind()) // これもinterface
	
	
	fmt.Println(reflect.ValueOf(reflect.ValueOf(&a).Elem()).Type().Kind())// これだとstruct になってしまう(なぜ??)
	fmt.Println(reflect.ValueOf(reflect.Indirect(reflect.ValueOf(&a))).Type().Kind()) // これもstruct

}

その他参考

https://kaminashi-developer.hatenablog.jp/entry/2022/11/08/095537 https://qiita.com/masakurapa/items/e1e49f9d6c864d97458f https://maku77.github.io/p/hxhzfbs/

サンプルコード

import (
	"reflect"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func Ptr[T any](a T) *T {
	return &a
}

func TestReflect(t *testing.T) {
	t.Run("assert_reflect", func(t *testing.T) {
		assert.Exactly(t, reflect.TypeOf(Ptr(0)).Kind(), reflect.Ptr)
		assert.Exactly(t, reflect.TypeOf((*int)(nil)).Kind(), reflect.Ptr)
		assert.Exactly(t, reflect.TypeOf(Ptr(0)).Elem().Kind(), reflect.Int)
		assert.Exactly(t, reflect.TypeOf((*int)(nil)).Elem().Kind(), reflect.Int)
		assert.Exactly(t, reflect.ValueOf(nil).Kind(), reflect.Invalid)
		assert.Exactly(t, reflect.ValueOf((*int)(nil)).Kind(), reflect.Pointer)
		assert.Exactly(t, reflect.ValueOf((*int)(nil)).Type().Kind(), reflect.Pointer)
		assert.Exactly(t, reflect.ValueOf((*time.Time)(nil)).Type().Kind(), reflect.Pointer)
		assert.Exactly(t, reflect.ValueOf((*int)(nil)).Elem().Kind(), reflect.Invalid)
		assert.Exactly(t, reflect.ValueOf((*int)(nil)).Type().Elem().Kind(), reflect.Int)

		assert.Exactly(t, reflect.New(reflect.TypeOf(0)).Elem().Int(), (int64)(0))
		assert.Exactly(t, *reflect.New(reflect.TypeOf((*time.Time)(nil)).Elem()).Interface().(*time.Time), time.Time{}) // nilからでも生成することができる。
		assert.Exactly(t, *reflect.New(reflect.ValueOf((*time.Time)(nil)).Type().Elem()).Interface().(*time.Time), time.Time{})

		assert.Exactly(t, reflect.ValueOf(nil).CanAddr(), false)
		assert.Exactly(t, reflect.ValueOf(time.Time{}).CanAddr(), false)
		assert.Exactly(t, reflect.ValueOf(&time.Time{}).CanAddr(), false)
		assert.Exactly(t, reflect.ValueOf(&time.Time{}).Elem().CanAddr(), true)
		assert.Exactly(t, reflect.ValueOf((*int)(nil)).Elem().CanAddr(), false)
		assert.Exactly(t, reflect.ValueOf((*time.Time)(nil)).Elem().CanAddr(), false)
		assert.Exactly(t, reflect.ValueOf(&struct{ t time.Time }{}).Elem().CanAddr(), true)
		assert.Exactly(t, reflect.ValueOf(&struct{ t time.Time }{}).Elem().Field(0).CanAddr(), true)
		assert.Exactly(t, reflect.ValueOf(&struct{ t *time.Time }{}).Elem().Field(0).CanAddr(), true)
		assert.NotEqual(t, reflect.ValueOf(&struct{ t *time.Time }{}).Elem().Field(0).Addr(), nil)
	})
}