Search code examples
gostructcomposition

Use same methods across multiple structs


I have a scenario where I have a few structs to model my database schema. What I want is to add a few methods to all those structs, so that I can use them in my handler. I achieved this using composition, but I have log utils in my parent struct, which is not getting initialized in child structs, because of which I am getting the following error

panic: runtime error: invalid memory address or nil pointer dereference

Suppose my parent struct is something like following

    //Model is the top level model instance
    type Model struct {
        utils *utils.Util
    }
    
    // New creates an instance of model
    func New(utils *utils.Util) *Model {
        return &Model{utils: utils}
    }
    
    // Initialize creates/opens database
    func (m *Model) Initialize() bool {
        db, err := m.openConnection()
        if err != nil {
            return false
        }
        defer db.Close()
        ctx, cancelfunc := context.WithTimeout(context.Background(), 5*time.Second)
        defer cancelfunc()
        err = db.PingContext(ctx)
        if err != nil {
            m.utils.Log.Errorf("FAILED::could not ping database because of %s", err.Error())
            return false
        }
        return true
    }

My Child Struct looks something like following

// User act as model for database
type User struct {
    *Model
    FirstName    string `sql:"firstName"`
}

And in my handler method, I have the following

  user := new(model.User)
  err := user.Initialize()

Everything works fine as expected, but throws an error only when PingContext returns an error. The error that I get is following

panic: runtime error: invalid memory address or nil pointer dereference

This works fine when I call this method directly from the parent struct. Is there any better way to achieve what I want to achieve or am I doing something wrong. Please suggest.

I know in case when the method is called from child struct it is complaining that m.utils is not initialized because of which I am getting an error, but incase of parent struct it is initialized and I am not getting error.


Solution

  • You embedded a *Model in the user struct, which is initially nil. When you call user.Initialize, the initialize method is called with a nil receiver. You either have to initialize that model to point to a non-nil struct, or embed non-pointer. Since you also have to initialize the Model, you can do this:

    type User struct {
        *Model
        FirstName    string `sql:"firstName"`
    }
    

    You have to initialize the Model and the utils in that model:

    u:=new(model.User)
    u.Model=model.New(utils)
    u.Initilize()