【问题标题】:How to initialize members in Go struct如何在 Go 结构中初始化成员
【发布时间】:2011-05-28 19:01:38
【问题描述】:

我是 Golang 的新手,所以其中的分配让我发疯:

import "sync"

type SyncMap struct {
        lock *sync.RWMutex
        hm map[string]string
}
func (m *SyncMap) Put (k, v string) {
        m.lock.Lock()
        defer m.lock.Unlock()

        m.hm[k] = v, true
}

然后,我只是打电话:

sm := new(SyncMap)
sm.Put("Test, "Test")

此时我得到一个零指针恐慌。

我已经通过使用另一个函数来解决它,并在new() 之后立即调用它:

func (m *SyncMap) Init() {
        m.hm = make(map[string]string)
        m.lock = new(sync.RWMutex)
}

但我想知道,是否有可能摆脱这个样板初始化?

【问题讨论】:

  • m.hm[k] = v, true 这毫无意义(试图为一个变量分配两个值),当被问到这个问题时,它是如何编译的?

标签: new-operator go


【解决方案1】:

你只需要一个构造函数。一个常用的模式是

func NewSyncMap() *SyncMap {
    return &SyncMap{hm: make(map[string]string)}
}

如果你的结构中有更多字段,启动一个goroutine作为后端,或者注册一个终结器,一切都可以在这个构造函数中完成。

func NewSyncMap() *SyncMap {
    sm := SyncMap{
        hm: make(map[string]string),
        foo: "Bar",
    }

    runtime.SetFinalizer(sm, (*SyncMap).stop)

    go sm.backend()

    return &sm
}

【讨论】:

  • 非常感谢!现在我记得,教程中有关于构造函数的内容,但是,作为一名 Java 开发人员,我认为它应该与 new 运算符有关,而不是与 New... 代码约定有关
  • 这可行,但不是最好的建议。 RWMutex 应该作为一个值,而不是一个指针。它的零值是一个即用型互斥体,这样可以避免显式构造函数。
  • 应该取不同的名字,因为它只是一个例子。如您所见,我还初始化了不属于原始结构的字段“foo”。 ;)
  • 编译器是否总是在堆上分配诸如 NewSyncMap() 所指向的结构?换句话说,要实现栈上的 C++ 对象初始化,我们是否必须改为创建一个修改现有结构的Init 函数?
【解决方案2】:

'Mue' 的解决方案不起作用,因为互斥体未初始化。以下修改有效:

package main

import "sync"

type SyncMap struct {
        lock *sync.RWMutex
        hm map[string]string
}

func NewSyncMap() *SyncMap {
        return &SyncMap{lock: new(sync.RWMutex), hm: make(map[string]string)}
}

func (m *SyncMap) Put (k, v string) {
        m.lock.Lock()
        defer m.lock.Unlock()
        m.hm[k] = v
}

func main() {
    sm := NewSyncMap()
    sm.Put("Test", "Test")
}

http://play.golang.org/p/n-jQKWtEy5

【讨论】:

  • 非常感谢!未初始化的互斥体会导致难以调试的细微错误。 Lock() 和 Unlock() 调用成功,但访问不同步。
【解决方案3】:

deamon 抓得好。 Mue 可能正在考虑将锁作为值而不是指针包含在内的更常见模式。由于 Mutex 的零值是一个随时可用的未锁定 Mutex,它不需要初始化,并且包含一个值是很常见的。作为进一步的简化,您可以通过省略字段名称来嵌入它。然后,您的结构获取 Mutex 的方法集。请参阅此工作示例http://play.golang.org/p/faO9six-Qx。我还拿出了延迟的使用。在某种程度上这是一个偏好和编码风格的问题,但由于它确实有一个小的开销,我倾向于不在小函数中使用它,尤其是在没有条件代码的情况下。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-11
    • 1970-01-01
    • 2021-03-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多