Golang: Interfaces stored as values; Methods unable to update structure fields
I have a tool that I am writing that provides some functionality that pulls information from a static database into multiple scripting languages that I am implementing into the tool.
I thought; "Hey, looks like a good use case for interfaces." So I defined an interface like this in the package scripts
type ScriptingLang interface {
RunScript(filename string) error
RunString(s string) error
Interpreter() error
Init() error
IsInit() bool
}
Then I save their map, so I can find them using a string defined like this in another package.
var ScriptingLangs = make(map[string]scripting.ScriptingLang)
and a function to register them. Also some helper functions like
func RunString(lang, s string) error {
if v, ok := ScriptingLangs[lang]; ok {
if !v.IsInit() {
v.Init()
}
return v.RunString(s)
} else {
return NoSuchLangErr
}
return nil
}
The problem I ran into is the seams that interfaces cannot have methods with pointer receivers. As a result, my Lua framework that implements ScriptingLang cannot store it * because it is stored in ScriptingLangs.
I tried to update the value stored in the map at the end of the functions that save the state and it did not update the value.
As I understand it, you shouldn't use pointers to interfaces, what are my options? I would like to really maintain interfaces so that I can do some neat stuff with git submodules.
Minimal example of my problem:
package main
import (
"fmt"
)
type ScriptingLang interface {
DoString(s string) error
Init() error
}
type Lua struct {
state string
}
func (l Lua) DoString(s string) error {
fmt.Printf("Doing '%v' with state '%v'\n", s, l.state)
return nil
}
func (l Lua) Init() error {
l.state = "Inited"
return nil
}
var lang ScriptingLang
func main() {
lang = Lua{}
lang.Init()
lang.DoString("Stuff")
}
source to share
If you want to change state, you need a pointer receiver and your method Init
doesn't have one. The fact that you store the value inside the interface doesn't matter.
In your minimal (-ish) example, change the method Init
(and any method that updates the state) to have a pointer sink and point the pointer inside the interface and everything works:
func (l *Lua) Init() error {
l.state = "Inited"
return nil
}
...
func main() {
lang = &Lua{}
lang.Init()
lang.DoString("Stuff")
}
This article can help: http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go
source to share