接口存储为值; 无法更新结构字段的方法

THU*_*OVE 4 pointers interface go

我有一个我正在编写的工具,它公开了一些函数,这些函数将信息从静态数据库中提取到我正在嵌入到工具中的几种脚本语言中.

我想; "嘿听起来像接口的一个很好的用例".所以我在我的包脚本中定义了这样的接口

type ScriptingLang interface {
    RunScript(filename string) error
    RunString(s string) error
    Interpreter() error
    Init() error
    IsInit() bool
}
Run Code Online (Sandbox Code Playgroud)

然后我存储了它们的地图,以便我可以通过在不同包中定义的字符串来查找它们.

var ScriptingLangs = make(map[string]scripting.ScriptingLang)
Run Code Online (Sandbox Code Playgroud)

以及注册它们的功能.还有一些小助手的功能就像

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
 }
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是接口不能有带指针接收器的方法.因此,我实现ScriptingLang的Lua结构无法保存它的*状态,因为它存储在ScriptingLangs中.

我已经尝试在保存状态的函数结束时更新存储在映射中的值,但它没有更新值.

据我所知,你不应该使用接口指针,所以我的选择是什么?我想保留接口,以便我可以用git子模块做一些简洁的东西.

我的问题的一个最小例子:

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")
}
Run Code Online (Sandbox Code Playgroud)

Pau*_*kin 7

如果你想改变状态,你需要一个指针接收器,而你的Init方法没有.您将值存储在接口中的事实没有任何区别.

在你的最小(-ish)示例中,更改Init方法(以及更新状态的任何方法)以使用指针接收器,并将指针指向接口内部并且一切正常:

func (l *Lua) Init() error {
    l.state = "Inited"
    return nil
}

...

func main() {
    lang = &Lua{}
    lang.Init()
    lang.DoString("Stuff")
}
Run Code Online (Sandbox Code Playgroud)

本文可能有所帮助:http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go