Как инициализировать элементы в Go struct


Я новичок в 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)
}

но интересно, можно ли избавиться от этой инициализации шаблона?

3 52

3 ответа:

вам просто нужен конструктор. Обычно используется шаблон

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
}

решение '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

хороший улов от deamon. Mue, возможно, думал о более распространенном шаблоне включения блокировки в качестве значения, а не указателя. Поскольку нулевое значение мьютекса является готовым к использованию разблокированным мьютексом, он не требует инициализации и включает его в качестве значения. В качестве дальнейшего упрощения вы можете внедрить его, опустив имя поля. Затем ваша структура получает набор методов мьютекса. См. этот рабочий пример,http://play.golang.org/p/faO9six-Qx. Также я вынул использование отсрочки. В какой-то степени это вопрос предпочтения и стиля кодирования, но поскольку он имеет небольшие накладные расходы, я не склонен использовать его в небольших функциях, особенно если нет условного кода.