Go言語におけるinterface{}とリフレクションを使ったパターン

September 19, 2013

この記事はQiitaの記事をエクスポートしたものです。内容が古くなっている可能性があります。

出力引数としてinterface{}を受け取る

設定したい変数のポインタをinterface{}として受け取る。 interface{}なので、任意の型を渡すことができる。 reflect.ValueOfreflect.Value型に変換する。 その後、Value.Elem()でポインタが指している先を取得して、Value.Set()で値を設定する。

http://play.golang.org/p/qsTwrL11mu

package main

import (
	"fmt"
	"reflect"
)

func set(p, v interface{}) error {
	pv := reflect.ValueOf(p)
	if pv.Kind() != reflect.Ptr {
		return fmt.Errorf("p must be pointer.")
	}

	vv := reflect.ValueOf(v)
	if pv.Elem().Kind() != vv.Kind() {
		return fmt.Errorf("p type and v type do not mutch")
	}

	pv.Elem().Set(vv)

	return nil
}

func main() {
	var hoge int
	fmt.Println(hoge)
	set(&hoge, 100)
	fmt.Println(hoge)
	fmt.Println(set(&hoge, 10.4))
}

関数をinterface{}で受け取る

関数は引数や戻り値を含めて型なので、引数や戻り値が一致しないと同じ型として扱うことができない。そのため、引数の型をinterface{}にしておき、任意の関数を渡し、リフレクションして呼び出す。

http://play.golang.org/p/fFmGNRlqcn

package main

import (
	"fmt"
	"reflect"
)

func call(f interface{}) {
	fv := reflect.ValueOf(f)
	if fv.Kind() != reflect.Func {
		panic("f must be func.")
	}
	fv.Call([]reflect.Value{})
}

func main() {
	f := func() {
		fmt.Println("hello!")
	}
	call(f)
}