简体   繁体   中英

Golang - add “inheritance” to structs

I would like to optimize my code, I have then the following situation:

I have a general struct where only one field gives the specification, let say a cache struct example:

# the main cache struct
type Cache struct {
  name             string
  memory_cache     map[string]interface{}
  mutex            *sync.Mutex
  ...              ...
  # common fields
}

# an element stored in the Cache.memory_cache map
type ElementA {
  name  string
  count int64
}

# an element stored in the Cache.memory_cache map
type ElementB {
  name  string
  tags  []string
}

My current solution follow the previously definition and I create a cache for each element (it must be so: one cache per element):

var cache_for_element_A Cache{}
var cache_for_element_B Cache{}

But in this way I must always cast the memory_cache when reading, even if I know already what is the content (then no cast-case should be needed).


The following code do what I would like to have, but it defines twice a lot of redundants/commons fields, for this reason I would like to find another solution.

type CacheForA struct {
  name             string
  memory_cache     map[string]ElementA{}
  mutex            *sync.Mutex
  ...              ...
  # common fields
}

type CacheForB struct {
  name             string
  memory_cache     map[string]ElementB{}
  mutex            *sync.Mutex
  ...              ...
  # common fields
}

Then, is it possible to define a field in the struct (more precisely Cache.memory_cache ) that can be further defined when the declaration occurs and without using interface ?

Struct embedding is the main thing you are looking for I think:

type Cache struct {
  name             string
  mutex            *sync.Mutex
}

type CacheA struct {
   Cache
   memory_cache map[string]ElementA{}
}  

Then you make a type of interface, say "Cacher" that has a set of methods for the things you need to do with your various caches (cacheA, CacheB). Create those methods for CacheA, CacheB, and assertions are only needed only for the return type:

type Cacher interface {
    GetItem(string) (interface{}, error)
}

If all your CacheFor types have that GetItem method, the interface will be fulfilled.

Still a fair amount of boilerplate, but this reduces the problem with redundancy in struct definitions. There are code generation tools if you don't want to type the boiler plate.

Go doesn't have generics, so there's no simple way of doing this, like you would in Java for instance ( class Cache<T>().... ).

One thing you can do is wrap your cache with a small typed function that just fetches objects from a generic cache and converts the interface to the right type. This just saves you from writing the interface conversion over and over in your code.

type ElemACache struct { 
   Cache
}

func (c *ElemeACache)Get(key string) ElemeA {
    return c.Cache.Get(key).(ElemeA) //of course add checks here
}

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