gotypestype-definition

Can't call methods on a type definition of a given type


I'm using Google Wire for dependency injection and I want 2 loggers (error and info). So I created the following provider:

type errorLogger *log.Logger
type infoLogger  *log.Logger

type Logger struct {
  Error errorLogger
  Info  infoLogger
}

func ProvideLogger() *Logger {
  return &Logger{
    Error: log.New(os.Stderr, "ERROR\t", log.Ldate|log.Ltime|log.Lshortfile),
    Info:  log.New(os.Stdout, "INFO\t", log.Ldate|log.Ltime),
  }
}

In my code I am referencing the loggers as so

h.Logger.Error

However, this doesn't give me access to the logger methods as I would assume it would (such as Println, Fatalf etc)

enter image description here

I assume I am referencing something incorrectly, just not sure what.


Solution

  • The new types defined as type errorLogger *log.Logger don't inherit the methods of the underlying type.

    See the Go specs, Type Declarations > Type Definitions:

    A defined type may have methods associated with it. It does not inherit any methods bound to the given type, but the method set of an interface type or of elements of a composite type remains unchanged

    type Mutex struct         { /* Mutex fields */ }
    func (m *Mutex) Lock()    { /* Lock implementation */ }
    func (m *Mutex) Unlock()  { /* Unlock implementation */ }
    
    // NewMutex has the same composition as Mutex but its method set is empty.
    type NewMutex Mutex
    
    // The method set of PtrMutex's underlying type *Mutex remains unchanged,
    // but the method set of PtrMutex is empty.
    type PtrMutex *Mutex
    

    It follows that Printf and other *log.Logger methods are not in the method set of errorLogger and infoLogger.

    You can use composition:

    type errorLogger struct {
       *log.Logger
    }
    

    and then you can initialize it with:

    &Logger{
        Error: errorLogger{
            Logger: log.New(os.Stderr, "ERROR\t", log.Ldate|log.Ltime|log.Lshortfile),
        },
    }