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

Viewed 62

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 Answers

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
Related