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")
}

      

+3


source to share


1 answer


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

+7


source







All Articles