Goのプログラミングでは、どんな型の引数でも受け取れる関数を作るのにinterface{}
を使います。
func v(x interface{}){
fmt.Println(x)
}
// v(1) => 1
// v("abc") => abc
しかし、interface{}
型な変数を、たとえばint
を引数にとる関数に渡すと、エラーになります。
func main(){
var x interface{} = 1
fmt.Println( add2(x) )
//=> cannot use x (type interface {}) as type int in argument to add2: need type assertion
}
func add2(n int) int{
return n + 2
}
このようなことをしたい場合は、castするか、switch式を使うことで、型を変換して関数に渡すことができます。
func main(){
var x interface{} = 1
var y interface{} = 5
// cast
if xi, ok := x.(int); ok{
fmt.Println( add2(xi) ) //=> 3
}
//switch
switch yi := y.(type){
case int:
// ここに入ってきた時は、yiの型はintとして扱われる
fmt.Println( add2(yi) ) //=> 5
case int64, int32, int8:
// ここに入ってきた時は、yiの型はint64, int32, int8のうち適切な型が選ばれている
}
}
func add2(n int) int{
return n + 2
}
パッケージ的なものを自作していると、
- どんな型の変数も渡せる
- 特定の型の関数を渡せる
ような関数が欲しくなることがあります。具体的には以下のように使える関数です
func exec(
v interface{}, // value
f interface{}, // valueを引数に実行するfunc
) interface{} {
fv := reflect.ValueOf(f)
if fv.Kind() != reflect.Func{
panic("2'nd argument is not func.")
}
rv := reflect.ValueOf(v)
return fv.Call([]reflect.Value{rv})[0]
}
// 以下のように使える
exec(5, func(i int) int{ return i * ( i + 1) })
exec("Tom", func(s string) string{ return "hello! " + s })
// 第一引数と、第二引数の引数の型が違うと、buildはできるが実行時にエラーが起きる
exec("Tom", func(i int) int{ return i * ( i + 1) })
build時に、エラーを出してほしいのですが、なかなかそうもいかない…