Consider some given interface and a function of an imaginary library that uses it like
// Binary and Ternary operation on ints
type NumOp interface {
Binary(int, int) int
Ternary(int, int, int) int
}
func RandomNumOp(op NumOp) {
var (
a = rand.Intn(100) - 50
b = rand.Intn(100) - 50
c = rand.Intn(100) - 50
)
fmt.Printf("%d <op> %d = %d\n", a, b, op.Binary(a,b))
fmt.Printf("%d <op> %d <op> %d = %d\n", a, b, c, op.Ternary(a,b,c))
}
A possible type implementing that interface could be
// MyAdd defines additions on 2 or 3 int variables
type MyAdd struct {}
func (MyAdd) Binary(a, b int) int {return a + b }
func (MyAdd) Ternary(a, b, c int) int {return a + b + c }
I am dealing with many different interfaces defining a few functions that in some cases need to be implemented using functions mostly working as NOP
-like operations, do not rely on any struct member and are only used in a single position in the project (no reusability needed).
Is there a simpler (less verbose) way in Go to define a (preferably) anonymous implementation of an interface using anonymous functions, just like (pseudo code, I know it's not working that way):
RandomNumOp({
Binary: func(a,b int) int { return a+b},
Ternary: func(a,b,c int) int {return a+b+c},
})
If the value implementing the interface must work (e.g. its methods must be callable without panic), then you can't do it.
Method declarations must be at the top level (file level). And to implement an interface that has more than 0 methods, that requires to have the method declarations somewhere.
Sure, you can use a struct and embed an existing implementation, but then again, it requires to already have an existing implementation, whose methods must already be defined "somewhere": at the file level.
If you need a "dummy" but workable implementation, them use / pass any implementation, e.g. a value of your MyAdd
type. If you want to stress that the implementation doesn't matter, then create a dummy implementation whose name indicates that:
type DummyOp struct{}
func (DummyOp) Binary(_, _ int) int { return 0 }
func (DummyOp) Ternary(_, _, _ int) int { return 0 }
If you need to supply implementation for some of the methods dynamically, you may create a delegator struct type which holds functions for the methods, and the actual methods check if the respective function is set, in which case it is called, else nothing will be done.
This is how it could look like:
type CustomOp struct {
binary func(int, int) int
ternary func(int, int, int) int
}
func (cop CustomOp) Binary(a, b int) int {
if cop.binary != nil {
return cop.binary(a, b)
}
return 0
}
func (cop CustomOp) Ternary(a, b, c int) int {
if cop.ternary != nil {
return cop.ternary(a, b, c)
}
return 0
}
When using it, you have the freedom to only supply a subset of functions, the rest will be a no-op:
RandomNumOp(CustomOp{
binary: func(a, b int) int { return a + b },
})
If you only need a value that implements an interface but you don't require its methods to be "callable" (to not panic if called), you may simply use an anonymous struct literal, embedding the interface type:
var op NumOp = struct{ NumOp }{}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With