Как инициализировать элементы в структуре Go - PullRequest
54 голосов
/ 21 декабря 2010

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

66 голосов
/ 21 декабря 2010

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

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

В случае наличия дополнительных полей в вашей структуре, запуска горутина в качестве бэкэнда или регистрации финализатора, все может быть сделано в этом конструкторе.

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

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

    go sm.backend()

    return &sm
}
9 голосов
/ 10 ноября 2012

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

5 голосов
/ 11 ноября 2012

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

...