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

289 Views Asked by At

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.

2

There are 2 best solutions below

0
On BEST ANSWER

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),
    },
}
0
On

The two new logger types, errorLogger and infoLogger, are new types and they do not have the methods of the underlying types. You should either use logger type directly without creating new types, or define the new logger types using embedding. When you define a new struct type and embed a logger, the new type will have the methods of the embedded type. When you define a new type like you did the new type will not have the methods of its base type.