如何对一个 interface{} 变量进行类型断言,以测试它是否为一个函数?

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

How do I do a type assertion on an interface{} variable to test if it is a function?

问题

我正在尝试编写一个函数,它可以接受任意类型的内容或者可以生成并返回任意类型的函数作为参数。为了实现这个目标,我需要能够通用地测试一个参数是否为函数,而不是测试它是否是返回类型为X的函数。我该如何做到这一点?可能看起来像下面的代码:

func Blah(arbitrary interface{}) {
    var value interface{}

    if function, ok := arbitrary.(func() interface{}); ok {
        value = function()
    } else {
        value = arbitrary
    }
    ...
}

这段代码目前无法正常工作。也许类型断言不适合在这里使用,或者我只是不知道正确的语法。如果有任何建议,我将不胜感激。目前我唯一知道的做法是将其拆分为两个函数,一个函数接受要存储的数据,另一个函数期望得到一个函数作为参数,但是当两种情况下的目标都只是获取一个值并将其传递给函数的其余部分时,这种做法似乎有些过度设计。

对此有什么想法吗?

英文:

I am attempting to write a function that accepts either some type of content of arbitrary type or a function that can generate and return an arbitrary type. To do this, I have to be able to generally test if an argument is a function without testing for whether it is a function of return type X. How do I do this? Might look something like the following:

func Blah(arbitrary interface{}) {
    var value interface{}

    if function, ok := arbitrary.(func interface{}); ok {
        value = function()
    } else {
        value = arbitrary
    }
    ...
}

This fails as is. Maybe a type assertion isn't the thing to use here. Or maybe I just don't know the syntax. Would appreciate any suggestions. Only thing I know to do at present is to divide this up into two functions, one that accepts data to be stored as is, and another that expects to get a function, but that seems overkill when in both cases the goal is simply to get a value and pass it on to the rest of the function.

Any ideas on this?

答案1

得分: 5

类型断言适用于特定类型。如果你知道函数的类型始终为func() interface{},那么可以使用以下代码:

if f, ok := arbitrary.(func() interface{}); ok {
    value = f()
} else {
    value = arbitrary
}

请注意,类型func() interface{}是一个返回类型为interface{}的函数,而不是具有任意返回类型的函数。

将任意函数包装为func() interface{}非常简单:

func hello() string { return "hello" }

wrapped := func() interface{} { return hello() }

如果无法将函数的返回类型设置为interface{},则需要使用反射来测试和调用函数:

func isFunction(v interface{}) (func() interface{}, bool) {
    rv := reflect.ValueOf(v)
    if rv.Kind() == reflect.Func {
        return func() interface{} {
            result := rv.Call(nil)
            if len(result) > 0 {
                return result[0].Interface()
            }
            return nil
        }, true
    }

    return nil, false
}

然后可以使用以下代码来调用函数:

if f, ok := isFunction(arbitrary); ok {
    value = f
} else {
    value = arbitrary
}

playground

英文:

Type assertions work on specific types. If you know that the type of the function always has type func() interface{}, then you can use:

if f, ok := arbitrary.(func() interface{}) {
    value = f()
} else {
    value = arbitrary
}

Note that the type func() interface{} is a function with return type interface{}, not a function with an arbitrary return type.

It's easy to wrap an arbitrary function to a func() interface{}:

func hello() string { return "hello" }

wrapped := func() interface{} { return hello() }

If you cannot arrange for the function to have return type interface{}, then you need to use reflection to test and call the function:

func isFunction(v interface{}) (func() interface{}, bool) {
  rv := reflect.ValueOf(v)
  if rv.Kind() == reflect.Func {
	return func() interface{} {
		result := rv.Call(nil)
		if len(result) > 0 {
			return result[0].Interface()
		}
		return nil
	}, true
  }

  return nil, false
}

---

if f, ok := isFunction(arbitrary); ok {
	value = f
} else {
    value = arbitrary
}

<kbd>playground</kbd>

huangapple
  • 本文由 发表于 2014年10月7日 02:26:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/26222456.html
匿名

发表评论

匿名网友

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

确定