在go中发现当前函数的返回类型

时间:2014-07-14 11:32:53

标签: reflection go

我有一个使用reflection和reflect.MakeFunc生成的函数,所以我直到运行时才真正拥有返回类型。

在MakeFunc正在使用的模板函数中,有没有办法确定被模板化的具体函数的返回类型?

基本上,有没有办法在运行时确定当前正在执行的函数的返回类型?

我知道Out方法:

fn.Type().Out(0)

我能够轻松找到函数的返回类型吗?

但是有没有办法找到当前正在执行的函数的返回类型(而不是显式传递的函数引用)。

3 个答案:

答案 0 :(得分:3)

在你谈论的情况下,当前正在执行的函数的返回类型总是[] reflect.Type(因为这是函数传递给reflect.MakeFunc必须返回的)。你真正想要的是调用你的函数的reflect.makeFuncStub函数的返回类型。

没有办法得到它(除了可能对调用堆栈进行一些奇怪的检查),但你可以创建一个提供信息的MakeFunc的增强版本:

package main

import (
    "fmt"
    "reflect"
)

// MakeFunc is like reflect.MakeFunc, but fn has an extra argument, retType, which
// is passed the desired return type.
func MakeFunc(typ reflect.Type, fn func(args []reflect.Value, retType reflect.Type) (results []reflect.Value)) reflect.Value {
    if n := typ.NumOut(); n != 1 {
        panic("wrong number of return values")
    }
    rt := typ.Out(0)
    return reflect.MakeFunc(typ, func(args []reflect.Value) (results []reflect.Value) {
        return fn(args, rt)
    })
}

func makeReturnOne(fptr interface{}) {
    fn := reflect.ValueOf(fptr).Elem()
    fn.Set(MakeFunc(fn.Type(), returnOne))
}

func returnOne(args []reflect.Value, retType reflect.Type) []reflect.Value {
    ret := reflect.New(retType).Elem()
    switch retType.Kind() {
    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
        ret.SetInt(1)
    case reflect.Float32, reflect.Float64:
        ret.SetFloat(1.0)
    default:
        panic("returnOne only supports int and float types")
    }
    r := ret.Interface()
    fmt.Printf("returning %v as %T\n", r, r)
    return []reflect.Value{ret}
}

func main() {
    var r1f func() float64
    var r1i func() int
    makeReturnOne(&r1f)
    makeReturnOne(&r1i)
    fmt.Println(r1f())
    fmt.Println(r1i())
}

答案 1 :(得分:2)

您应该fn.Type().Out(0).Kind()检查example

func main() {    
    fnTmpl := func(in []reflect.Value) []reflect.Value {
        return []reflect.Value{in[0]}
    }
    makeFn := func(fptr interface{}) {
        fn := reflect.ValueOf(fptr).Elem()
        fn.Set(reflect.MakeFunc(fn.Type(), fnTmpl))
    }
    var nFn func(int) int
    makeFn(&nFn)
    kind := reflect.TypeOf(nFn).Out(0).Kind()
    switch kind {
    case reflect.Int:
        fmt.Println("int")

    }
}

答案 2 :(得分:1)

我可能误解了你想要实现的目标,但为什么不采取你正在回归的那种价值呢?修改OneOfOne的示例如下:

fnTmpl := func(in []reflect.Value) (res []reflect.Value) {
    res = []reflect.Value{in[0]}
    fmt.Println("Returned:", res[0].Kind())
    return res
}

游乐场:http://play.golang.org/p/EujmxyGRrI