在Go中编写一个通用的绑定器

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

Writing a generic binder in Go

问题

考虑以下函数——第二个参数的绑定器。

func bindSecond(value interface{}, f func(a interface{}, b interface{})) func(c interface{}) {
    return func(arg interface{}) {
        f(arg, value)
    }
}

考虑一个函数

func f(x int, y int) {}

当尝试将其作为绑定器的参数时,Go编译器报错:

cannot use f (type func(int, int)) as type func(interface {}, interface {}) in argument to bindSecond.

请问你能否为我提供在Go中实现绑定器的正确方法?

英文:

Consider the following function -- a binder of the second argument.

func bindSecond(value interface{}, f func(a interface{}, b interface{})) func (c interface{}) {
    return func(arg interface{}) {
	    f(arg, value)
    }
}

Consider a function

func f(x int, y int) {}

When trying to use it as a parameter in binder, go compiler says:

cannot use f (type func(int, int)) as type func(interface {}, interface {}) in argument to bindSecond.

Could you please suggest me the proper way of implementing binders in go (golang)?

答案1

得分: 4

interface{}替换为int,它就会工作。

或者更重要的是,尝试使用Go提供的功能来找到解决方案,而不是试图从不同的范式中强行解决问题。

英文:

Replace interface{} with int and it will work.

Or, more to the point, try to find a solution to your original problem using the features Go provides, instead of trying to force a solution from a different paradigm.

答案2

得分: 4

我明白你想做什么,一些模板对吧?但是这种方式行不通。你的 f func(a interface{}, b interface{}) 参数不是一个接口,所以它必须是匹配的类型。你可以通过传递 f interface{} 并使用 reflect 包来实现你想要的效果。

这是一个简单的示例:

package main

import (
	"fmt"
	"reflect"
)

func bindSecond(value interface{}, f interface{}) func(c interface{}) {
	return func(arg interface{}) {
		reflect.ValueOf(f).Call([]reflect.Value{reflect.ValueOf(arg), reflect.ValueOf(value)})
	}
}

func main() {
	sum := func(x int, y int) { fmt.Println(x + y) }
	inc := bindSecond(1, sum)
	inc(10)
}

// 输出 11

这样是可行的,但不太美观。如果发生任何意外情况,例如 f 不可调用或不接受恰好两个参数,或者你向 inc 传递了错误的类型,它会在运行时引发 panic。编译器将无法再帮助你。

英文:

I see what you're trying to do, some templates, right? But this is not going to work this way. Your f func(a interface{}, b interface{}) argument is not an interface, so it must be of the matching type. You could achieve what you want by passing f interface{} and then manipulate it with reflect package.

Some naive example:

package main

import (
	"fmt"
	"reflect"
)

func bindSecond(value interface{}, f interface{}) func(c interface{}) {
	return func(arg interface{}) {
		reflect.ValueOf(f).Call([]reflect.Value{reflect.ValueOf(arg), reflect.ValueOf(value)})
	}
}

func main() {
	sum := func(x int, y int) { fmt.Println(x + y) }
	inc := bindSecond(1, sum)
	inc(10)
}

// Prints 11

Doable, but not very pretty. And panics in runtime if anything unexpected happens, for example f is not callable and doesn't take exactly two arguments. Or you pass a wrong type to inc. Complier won't help you anymore.

huangapple
  • 本文由 发表于 2015年5月2日 20:13:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/30002165.html
匿名

发表评论

匿名网友

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

确定