Search code examples
gogo-modules

cannot define new methods on non-local type models.Meter


I want to put all my models in a shared Common lib.

So, I made a new repo: gitlab.com/xxx/common

Inside I put a package: models

Here is the definition of an object:

type Meter struct {
    ID           string
    OperationID  string
    Type         ConsoProd
    Unit         string
    Timestep     time.Duration
    Measures     []Measure 
    FetchMethod  AcquisitionMethod
    Metadata     interface{}
}

Now, I want to use it in an external project, I do:

go get gitlab.com/xxx/common

And Go Modules will download it.

I import use it like that:

import "gitlab.com/xxx/common/models"

//String transparent method
func (meter models.Meter) String() string {
    var stringifyMeter string
    stringifyMeter += "Meter " + meter.ID + " is a " + meter.Type.String() + " and compute in operation #" + meter.OperationID + "."
    return stringifyMeter
}

But Goland will not resolve it, and when I compile, I get:

cannot define new methods on non-local type models.Meter

Why is it happening and what can I do to fix it ?


Solution

  • It is not allowed to define methods outside the package where the type is defined. This leaves you with a couple of options:

    1. Define the methods in the models package. That's the simplest approach when dealing with your own code but of course won't work for 3rd-party types.

    2. Create a regular function instead of a method (func String(meter models.Meter) string). That might be less idiomatic, though (especially for the String method), and also does not have access to private fields (unless you define the function in the models package, in which case you could just define the method instead).

    3. Create a new type embedding the original type. That would be a bit cumbersome to use but allows you to extend existing behavior. Something like this:

    `

    package main
    
    import (
        "fmt"
        "time"
    )
    
    func main() {
        myTime := MyTime{time.Now()}
        fmt.Println(myTime)        /* behaves as time.Time */ 
        fmt.Println(myTime.Foo())  /* also has extra methods */
    }
    
    type MyTime struct {
      time.Time
    }
    
    func (m MyTime) Foo() string {
      return "foo"
    }