发现Go语言中当前函数的返回类型。

huangapple go评论79阅读模式
英文:

Discover the return type of the current function in go

问题

我有一个使用反射和reflect.MakeFunc生成的函数,所以在运行时我实际上并没有返回类型。

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

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

我知道有一个Out方法:

fn.Type().Out(0)

我可以很容易地找到一个函数的返回类型?

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

英文:

I have a function that is being generated using reflection and reflect.MakeFunc, so I don't actually have the return type until runtime.

Inside the template function that MakeFunc is using, is there a way to determine the return type of the concrete function being templated?

Essentially, is there a way to determine the return type iof the currently executing function at runtime?

I know about the Out method:

fn.Type().Out(0)

And I can find the return type of a function easily enough?

But is there a way to find the return type of the currently executing function (as opposed to an explicit passed function reference).

答案1

得分: 3

你应该检查fn.Type().Out(0).Kind(),例如:

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")

    }
}
英文:

You should check fn.Type().Out(0).Kind(), for 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

得分: 3

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

没有办法直接获取它(除非也许通过一些奇怪的调用堆栈检查),但你可以创建一个增强版的MakeFunc函数来提供这个信息:

package main

import (
	"fmt"
	"reflect"
)

// MakeFunc类似于reflect.MakeFunc,但是fn有一个额外的参数retType,用于传递所需的返回类型。
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())
}

希望对你有帮助!

英文:

In the case you are talking about, the return type of the currently executing function is always []reflect.Type (because that is what a function passed to reflect.MakeFunc must return). What you really want is the return type of the reflect.makeFuncStub function that called your function.

There is no way to get that (except perhaps some strange inspection of the call stack), but you can make an enhanced version of MakeFunc that provides the information:

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())
}

答案3

得分: 1

我可能对你试图实现的目标有误解,但为什么不直接获取你返回值的类型呢?可以修改OneOfOne的示例代码如下:

fnTmpl := func(in []reflect.Value) (res []reflect.Value) {
    res = []reflect.Value{in[0]}
    fmt.Println("返回值类型:", res[0].Kind())
    return res
}

Playground: http://play.golang.org/p/EujmxyGRrI

请注意,这只是将返回值的类型打印出来,如果你需要进行其他操作,请提供更多详细信息。

英文:

I might have misinterpreted what you are trying to achieve, but why not just take the kind of the value you are returning? Modifying OneOfOne's example as follows:

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

Playground: http://play.golang.org/p/EujmxyGRrI

huangapple
  • 本文由 发表于 2014年7月14日 19:32:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/24735590.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定