简体   繁体   中英

Collections of generic structs with embedded locks in golang

Below I have an example of one structure which embeds another. I'm trying to figure out how to pass the more specific structure pointer to be stored in a less specific one. You can think of it as a collection. Wrapping in an interface doesn't seem to work, as doing so would make a copy, which isn't valid for structs with locks. Ideas?

package stackoverflow

import "sync"

type CoolerThingWithLock struct {
    fancyStuff string
    ThingWithLock
}

func NewCoolerThingWithLock() *CoolerThingWithLock {
    coolerThingWithLock := &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 := &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)
}

Error: cannot use thingTwo (type *CoolerThingWithLock) as type *ThingWithLock in argument to thingOne.AddChild

It's impossible to store the wrapping type in []*ThignWithLock since go has no notion of structural subtyping.

Your assertion that an interface will result in copying is incorrect , and you can get the desired effect by doing:

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

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

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

As long as the interface is implemented on a *ThingWithLock and not ThingWithLock , there will be no copying of the receiver struct itself, only the pointer to the struct will be copied on the stack.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM