I made an interface meant to do basic math with struct values. The interface's math functions always update the values of the struct's pointer.
My problem is that at some point, I want to overwrite the value to the initial value but I only have the interface to work with. Because it is a pointer interface (not 100% sure if this is what people call it), I am unable to "clone" the initial value of the struct in order to overwrite later.
Please also note I'm trying my best to avoid reflection.
Here is my code. Will probably make a lot more sense than me trying to explain it:
package main
import (
"fmt"
)
type mather interface {
add(mather) mather
sub(mather) mather
}
type float struct {
value float64
}
func (f *float) add(m mather) mather {
f.value += m.(*float).value
return f
}
func (f *float) sub(m mather) mather {
f.value -= m.(*float).value
return f
}
func (f *float) get() interface{} {
return *f
}
func main() {
var a, b, c mather
a = &float{2} // this could be any time. approximitly 10 possible types
b = &float{7} // this could be any time. approximitly 10 possible types
// float can't be used again below, only mather
c = a
fmt.Println(a)
fmt.Println(b)
fmt.Println()
// a's math
doMath(a)
// now math is done, we need to reset the value from before the math was done
// set *a equal to *c. (a == &float{2})
resetMath(a, c)
// b's math
doMath(b)
// now math is done, we need to reset the value from before the math was done
// set *b equal to *c. (b == &float{7})
resetMath(b, c)
fmt.Println(a)
fmt.Println(b)
}
func doMath(m mather) {
m.add(&float{3})
}
func resetMath(m mather, r mather) {
m = r
}
You need to define clone
and set
method in mather
interface, i.e.:
type mather interface {
add(mather) mather
sub(mather) mather
get() interface{}
clone() mather
set(v mather)
}
The implementation of get
, set
and clone
in float
type looks like:
func (f *float) get() interface{} {
return f.value
}
func (f *float) clone() mather {
return &float{f.value}
}
func (f *float) set(v mather) {
switch v := v.(type) {
case *float:
f.value = v.value
//handle other possible types...
default:
//handle unknown types
}
}
See working example in Playground. The only complicated parts is set
in which you should determined the underlying type. Here you can use type switch
to get underlying type, then assign it to float
. Similar codes need to be added in the other underlying types (you mention that there are 10 possible types).
You can do it using simple addressing operators if you have a reference of the underlying type, which you can get through type assertion if necessary without having to resort to reflection. Once you have a *float
, it's easy:
f := &float{2}
var a, b *float
a = f
b = new(float)
*b = *f // Assign the value pointed to by f to the value pointed to by b
In this case your local vars are now *float
instead of mather
, but at least in your example that doesn't matter. If it does matter, as noted above, you can use type assertions.