【问题标题】:Interfaces stored as value; Methods unable to update struct fields接口存储为值;无法更新结构字段的方法
【发布时间】:2015-07-14 15:46:22
【问题描述】:

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

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

type ScriptingLang interface {
    RunScript(filename string) error
    RunString(s string) error
    Interpreter() error
    Init() error
    IsInit() bool
}

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

var ScriptingLangs = make(map[string]scripting.ScriptingLang)

以及注册它们的功能。还有一些小助手功能,例如

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
 }

我遇到的问题是接口不能有带有指针接收器的方法。结果,我实现 ScriptingLang 的 Lua 结构无法保存它的 *state,因为它存储在 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")
}

【问题讨论】:

  • 你是说指针类型不能实现接口?可以肯定的是,他们可以。你能创建一个最小的例子来展示你遇到的问题吗?目前,您的问题有很多上下文,但没有一个重要的细节。
  • 没有。我的印象是接口的指针无法使用调用方法。此外,结构无法更新它的任何字段,因为接口不允许使用指针方法。我确实更新了一个最小的例子来说明正在发生的事情。提前感谢您的帮助!
  • 顺便说一句,一些旁注:当naming 尽量避免口吃(例如scripting.Langscripting.ScriptingLag)。错误变量通常被命名为Err… 和错误类型…Error(例如var ErrNoSuchLang = errors.New(…)type SomeCategoryError …)。如果您打算通过 goroutines 使用任何这些,请注意数据竞争;照原样您的Init 示例对于并发是不安全的(如果您希望调用者处理它,那很好); sync.Oncerace detector 在这种情况下会有所帮助。
  • 除了比赛,这一切都已修复。 Godoc.org 的 linter 大部分都困扰着我。该工具目前不使用任何 Goroutines。谢谢戴夫!

标签: pointers interface go


【解决方案1】:

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

在您的最小(-ish)示例中,将 Init 方法(以及任何更新状态的方法)更改为具有指针接收器,并在接口内指向一个指针,一切正常:

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

...

func main() {
    lang = &Lua{}
    lang.Init()
    lang.DoString("Stuff")
}

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

【讨论】:

  • 虽然不能满足界面; Lua 没有实现 ScriptingLang(Init 方法有指针接收器)
  • 我现在正忙着捂脸。无论出于何种原因,我都试图将接口内的指针存储为 *ScriptingLang。非常感谢您帮助我理解这一点。
  • 真的很好的解释和很好的例子。为我节省了很多时间。谢谢。
猜你喜欢
  • 2019-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-22
  • 2017-10-20
  • 2015-01-06
  • 1970-01-01
相关资源
最近更新 更多