Коллекции универсальных структур со встроенными блокировками в golang

#go

#Вперед

Вопрос:

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

 package stackoverflow

import "sync"

type CoolerThingWithLock struct {
    fancyStuff string
    ThingWithLock
}

func NewCoolerThingWithLock() *CoolerThingWithLock {
    coolerThingWithLock := amp;CoolerThingWithLock{}
    coolerThingWithLock.InitThingWithLock()
    return coolerThingWithLock
}

type ThingWithLock struct {
    value    int
    lock     sync.Mutex
    children []*ThingWithLock
}

func (thingWithLock *ThingWithLock) InitThingWithLock() {
    thingWithLock.children = make([]*ThingWithLock, 0)
}

func NewThingWithLock() *ThingWithLock {
    newThingWithLock := amp;ThingWithLock{}
    newThingWithLock.InitThingWithLock()
    return newThingWithLock
}

func (thingWithLock *ThingWithLock) AddChild(newChild *ThingWithLock) {
    thingWithLock.children = append(thingWithLock.children, newChild)
}

func (thingWithLock *ThingWithLock) SetValue(newValue int) {
    thingWithLock.lock.Lock()
    defer thingWithLock.lock.Unlock()

    thingWithLock.value = newValue

    for _, child := range thingWithLock.children {
        child.SetValue(newValue)
    }
}

func main() {
    thingOne := NewThingWithLock()
    thingTwo := NewCoolerThingWithLock()
    thingOne.AddChild(thingTwo)

    thingOne.SetValue(42)
}
  

Ошибка: не удается использовать thingTwo (тип * CoolerThingWithLock) в качестве типа
*ThingWithLock в аргументе thingOne.addChild

Ответ №1:

Невозможно сохранить тип упаковки в []*ThignWithLock , поскольку go не имеет понятия о структурном подтипе.

Ваше утверждение о том, что интерфейс приведет к копированию, неверно, и вы можете получить желаемый эффект, выполнив:

 type InterfaceOfThingThatParticipatesInAHierarchy interface {
    AddChild(InterfaceOfThingThatParticipatesInAHierarchy)
    SetValue(int)
}

type ThingWithLock struct {
    ...
    children []InterfaceOfThingThatParticipatesInAHierarchy
}

func (thingWithLock *ThingWithLock) AddChild(newChild InterfaceOfThingThatParticipatesInAHierarchy) { ... }
  

До тех пор, пока интерфейс реализован на *ThingWithLock и не ThingWithLock , не будет копирования самой структуры получателя, в стек будет скопирован только указатель на структуру.

Комментарии:

1. Потрясающе, это именно то, что я искал. Спасибо за помощь! 🙂