如何在Go语言中将具有不同类型参数的可变参数函数作为值传递?

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

How to pass a variadic function with different type of arguments as a value in golang?

问题

我想将一个可变参数函数作为另一个函数的参数传递。我尝试了以下代码,但它没有起作用。请给我一些建议。

type Action func(args ...any) error

func ActionType(f Action) reflect.Type {
	return reflect.TypeOf(f)
}
func main() {

	f1 := func(int, string) error {}
	f2 := func(int) error {}
	f3 := func() error {}
	fmt.Println(ActionType(f1), ActionType(f2), ActionType(f3)) //error here
}

我想知道如何解决这个问题。

英文:

I want to pass a variadic function as the parameter of another function.I tried like the following code, but it didn't work.Please give me some of advice.

type Action func(args ...any) error

func ActionType(f Action) reflect.Type {
	return reflect.TypeOf(f)
}
func main() {

	f1 := func(int, string) error {}
	f2 := func(int) error {}
	f3 := func() error {}
	fmt.Println(ActionType(f1), ActionType(f2), ActionType(f3)) //error here
}

答案1

得分: 1

你正在声明f1f2f3作为匿名函数,它们的类型分别为func(int, string) errorfunc(int) errorfunc() error,其中没有一个是func(...any) error。要创建一个Action,你需要这样做:f4 := func(...any) error { //stuff }。在Go语言中,类型非常严格,其可变参数函数基本上只是接受一个切片参数(作为最后一个参数)的语法糖。大致上,func(...any)等同于func([]any),尽管它们甚至不是相同的类型。

错误消息基本上告诉你这一点,尽管更简洁。

./prog.go:18:25: 无法将类型为 func(int, string) error  f1 用作参数传递给 ActionType 中的 Action 类型
./prog.go:18:41: 无法将类型为 func(int) error  f2 用作参数传递给 ActionType 中的 Action 类型
./prog.go:18:57: 无法将类型为 func() error  f3 用作参数传递给 ActionType 中的 Action 类型

Icza在评论中提出了一种使ActionType()接受任何函数的方法。我之前使用过的另一种方法,可能更加类型安全,是使ActionType()接受一个没有参数的函数(并返回一个错误,或者其他你需要返回的内容)。然后,使用闭包来捕获Action函数的"参数"。例如:

package main

import (
	"fmt"
	"reflect"
)

type Action func() error

func ActionType(f Action) reflect.Type {
	// 调用 f 执行操作
	err := f()
	if err != nil {
		fmt.Println(err)
	}
	// 做其他事情...
	return reflect.TypeOf(f)
}

// 这本质上是相同的,因为 Action 的底层类型是 "func() error"
func ActionType2(f func() error) reflect.Type { return reflect.TypeOf(f) }

func main() {
	msg := "hello world"
	number := 42
	action1 := func() error {
		fmt.Println(msg)
		return nil
	}
	action2 := func() error {
		number *= 2
		return nil
	}

	fmt.Println(ActionType(action1))
	fmt.Println(ActionType(action2))
	fmt.Println(ActionType2(action2)) // 不修改 number
	fmt.Println(number)
}

输出

hello world
main.Action
main.Action
func() error
84
英文:

You're declaring f1, f2, and f3 as anonymous functions with types func(int,string) error, func(int) error, and func() error respectively, none of which is func(...any) error. To create an Action you'd have to do f4 := func(...any) error { //stuff } for example. Types are pretty strict in Go, and its variadic functions are basically just syntactic sugar for accepting a single slice argument (as the last arg). Roughly, func(...any) equals func([]any), though even these aren't even the same type.

The error messages basically tell you this, though more tersely.

./prog.go:18:25: cannot use f1 (variable of type func(int, string) error) as type Action in argument to ActionType
./prog.go:18:41: cannot use f2 (variable of type func(int) error) as type Action in argument to ActionType
./prog.go:18:57: cannot use f3 (variable of type func() error) as type Action in argument to ActionType

Icza suggested in the comments one way to make ActionType() take any function. Another way that I have used before, and is perhaps a little more type safe, is to make ActionType() take a function with no arguments (and return an error, or whatever else you need to return). Then, use a closure to capture the "arguments" for the Action func. For example:

package main

import (
	"fmt"
	"reflect"
)

type Action func() error

func ActionType(f Action) reflect.Type {
	// call f to perform the action
	err := f()
	if err != nil {
		fmt.Println(err)
	}
	// do other things ...
	return reflect.TypeOf(f)
}

// this is essentially the same since Action's underlying type
// is "func() error"
func ActionType2(f func() error) reflect.Type { return reflect.TypeOf(f) }

func main() {
	msg := "hello world"
	number := 42
	action1 := func() error {
		fmt.Println(msg)
		return nil
	}
	action2 := func() error {
		number *= 2
		return nil
	}

	fmt.Println(ActionType(action1))
	fmt.Println(ActionType(action2))
	fmt.Println(ActionType2(action2)) // doesn't modify number
	fmt.Println(number)
}

Output

hello world
main.Action
main.Action
func() error
84

huangapple
  • 本文由 发表于 2022年9月1日 19:49:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/73568861.html
匿名

发表评论

匿名网友

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

确定