4 回答
TA贡献1794条经验 获得超8个赞
这是不可能的。原因之一是传递参数的机制因函数而异,使用interface{}
arg 并不意味着“接受任何东西”。例如,一个以结构为参数的函数将接收该结构的每个成员,但一个以包含该结构的 interface{} 的函数将接收两个字,一个包含结构的类型,另一个包含指向它。
因此,在不使用泛型的情况下,实现这一点的唯一方法是使用适配器函数。
TA贡献2011条经验 获得超2个赞
使用反射包来处理具有任意参数和结果类型的函数。
func decorate(inner interface{}, args interface{}) interface{} {
fmt.Println("Before inner")
result := reflect.ValueOf(inner).Call([]reflect.Value{reflect.ValueOf(args)})
fmt.Println("After inner")
return result[0].Interface()
}
在操场上运行代码。
与decorate问题中的函数一样,此答案中的函数假定一个参数和一个结果。必须修改该函数以处理其他函数类型。
OP 应考虑问题中提出的匿名包装函数与此处使用反射包之间的权衡。通过反射 API 调用函数比通过匿名包装器调用函数慢。反射 API 也失去了类型安全性。匿名包装函数增加了冗长性。
TA贡献1784条经验 获得超2个赞
作为记录,随着 Go 1.18 和泛型的引入,该decorator功能变得几乎微不足道。
您可以这样声明类型约束:
type UnaryFunc[T any] interface {
func(T) T
}
约束本身被参数化T以允许接受和返回任意类型的一元函数。
然后在decorate函数中使用类型参数实例化约束。签名变为:
decorate[T any, F UnaryFunc[T]](inner F, arg T) T
多亏了类型推断,您可以只将具体参数传递给函数,并且两者T都是F明确的。
没有命名约束的示例替代方案:
// accept and return T
decorate[T any](inner func(T) T, arg T) T
// only return T
decorate[T any](inner func() T) T
// return T and error
decorate[T any](inner func(T) (T, error), arg T) (T, error)
// N-ary function
decorate[T, U any](inner func(T, U) (T, error), argt T, argu U) (T, error)
明显的限制是接口约束UnaryFunc只指定了只接受和返回一个 arg 类型的函数T。你不能这样做,因为接口约束的类型集可能包括支持相同操作的类型——并且使用一个 arg 调用与使用 N 个 args 调用不兼容。
完整程序:
package main
import (
"fmt"
)
type UnaryFunc[T any] interface {
func(T) T
}
func decorate[T any, F UnaryFunc[T]](inner F, arg T) T {
fmt.Println("before inner")
result := inner(arg)
fmt.Println("after inner")
return result
}
func funcA(arg int) int {
fmt.Println("inside A with:", arg)
return arg
}
func funcB(arg string) string {
fmt.Println("inside B with:", arg)
return arg
}
func main() {
// this works
decorate(funcA, 200)
// this also works
decorate(funcB, "Func B")
}
游乐场:https ://go.dev/play/p/3q01NiiWsve
TA贡献1818条经验 获得超7个赞
有没有办法将 func(string) string 类型的现有函数转换为 func(interface{}) interface{} 类型,以便它也可以传递给装饰器函数,而无需将其包装在新的匿名函数中(见 funcB)?
不,就这么简单:不。
- 4 回答
- 0 关注
- 146 浏览
添加回答
举报