5

I have code that has following structure:

// $GOPATH/experiments/interfaceexport/printer/printer.go
package printer

import "fmt"

type ResourcePrinter interface {
    PrintSomething()
}

type JSONPrinter struct {
    IsGeneric bool
}

func (printer *JSONPrinter) PrintSomething() {
    fmt.Println("JSON")
}

// $GOPATH/experiments/interfaceexporter/printerretriever/printerretriever.go
package printer

import "experiments/interfaceexporter/printer"

func GetPrinter() printer.ResourcePrinter {
  return &printer.JSONPrinter{IsGeneric: true}
}


// $GOPATH/experiments/interfaceexport/main.go
import "experiments/intefaceexport/printerretriever"

func main() {
  printer := printerretriever.GetPrinter()

  printer.PrintSomething() // "JSON"
  // interfaceexport/main.go:13: printer.IsGeneric undefined (type printer.ResourcePrinter has no field or method IsGeneric)
  if printer.IsGeneric {
    printer.PrintSomething()
  }
}

When I do go run main.go I get following error:

interfaceexport/main.go:13: printer.IsGeneric undefined (type printer.ResourcePrinter has no field or method IsGeneric)

Why do I get above error even though IsGeneric is exported?

Waseem
  • 8,232
  • 9
  • 43
  • 54

2 Answers2

12

printer.ResourcePrinter is an interface, not the actual instance JSONPrinter, which does have access to IsGeneric

You would need to add a method IsGeneric() to your interface (and implement it in JSONPrinter) in order to be able to use that interface as you want.

See "golang how to access interface fields": you could also extract the dynamic value held by the interface variable through a type assertion:

dynamic_value := printer.(JSONPrinter)

Then dynamic_value would have access to the IsGeneric attribute.

See more at "How to access attribute of interface".


Even though compiler knows that printer.ResourcePrinter is an interface, it says that IsGeneric could also be a field.

The dynamic value of the interface can have field (see "Get all fields from an interface")

The no field part, when applied to an interface, can refer to an embedded type, the unqualified type’s name acts as the field name.

type ReadWriter interface {
    Read(b Buffer) bool
    Write(b Buffer) bool
}

type File interface {
    ReadWriter  // same as adding the methods of ReadWriter
    Locker      // same as adding the methods of Locker
    Close()
}

You also see that kind of error message when using a pointer to an interface (when the interface itself includes a pointer of sorts: "Go: What's the meaning of interface{}?" and "Cast a struct pointer to interface pointer in Golang")

See issue 10700

When using a new, unfamiliar package, programmers occasionally make the error of using a pointer to an interface type instead of the interface type directly.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • I think I have a beef with "has no field" field part in the error message. Even though compiler knows that printer.ResourcePrinter is an interface, it says that IsGeneric could also be a field. AFAIK there is no way in Go one can define fields, like structs, for interfaces. – Waseem May 20 '17 at 09:18
0

Simple, your interface has no method IsGeneric:

type ResourcePrinter interface {
    PrintSomething()
}
Alex Pliutau
  • 21,392
  • 27
  • 113
  • 143