I have the following struct
:
// fninfo holds a function and its arity.
type fninfo struct {
arity int // number of arguments that fn takes
fn any // fn must take string arguments and return one string
}
and a map of it:
var fnmap = map[string]fninfo{
"not": fninfo{
arity: 1,
fn: func(a string) string // body omitted...
},
"add": fninfo{
arity: 2,
fn: func(a, b string) string // body omitted...
},
// more items...
}
What I want to do is, with any fninfo
,
pop fninfo.arity
number of string
s from a stack (implementation omitted)
and call fninfo.fn
with all the popped string
s as arguments,
in a way similar to this:
info := fnmap[fnname]
args := make([]string, info.arity)
for i := 0; i < len(args); i++ {
if args[i], err = stk.pop(); err != nil {
// Handle error...
}
}
info.fn(args...)
However, this is forbidden for two reasons:
info.fn
cannot be directly called because it is of typeany
(interface{}
)info.fn
cannot be called with a slice as its arguments because it is not a variadic function
Currently, all the functions I have take between 1-3 arguments, so as a workaround, I am manually popping each item and checking each type assertion:
info := fnmap[fnname]
if fn, ok := info.fn.(func(string) string); ok {
a, err := stk.pop()
if err != nil {
// Handle error...
}
stk.push(fn(a))
} else if fn, ok := info.fn.(func(string, string) string); ok {
a, err := stk.pop()
if err != nil {
// Handle error...
}
b, err := stk.pop()
if err != nil {
// Handle error...
}
stk.push(fn(a, b))
} else if fn, ok := info.fn.(func(string, string, string) string); ok {
a, err := stk.pop()
if err != nil {
// Handle error...
}
b, err := stk.pop()
if err != nil {
// Handle error...
}
c, err := stk.pop()
if err != nil {
// Handle error...
}
stk.push(fn(a, b, c))
}
This is very long and repetitive, and it becomes unmaintainable should I add functions with 4, 5, or even more arguments.
How can I bypass the two problems I listed above and have something similar to my second last example? Is this possible to achieve in Go? without reflection, and if not, with?