Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Go can I return a struct that meets an interface without access to that interface?

Tags:

interface

go

I think the best way to explain this is by example, so here it is:

package main

import (
    "fmt"
)

// Greeter greets with a Greeting.
type Greeter interface {
    Greet() Greeting
}

// A Greeting has a string representation.
type Greeting interface {
    String() string
}

type Hello struct {}

// Hello greets by returning itself...
func (h *Hello) Greet() *Hello {
    return h
}

// ...because Hello also has a string representation.
func (h *Hello) String() string {
    return "Hello"
}

// But Go says Hello doesn't implement Greeter.
func main() {
    var g interface{} = &Hello{}
    g, ok := g.(Greeter)
    fmt.Println(ok)
}

This prints false. You can run and play with it: https://play.golang.org/p/A_2k_ku_Q2

In my real case the struct Hello and the interfaces for Greeter and Greeting are in different packages that do not import each other and I wanted to keep it that way. I'm perhaps missing some understanding of interfaces in Go but after reading so much about it I still can't put my finger on it. Would you guys have any pointers for me? Maybe another approach for the problem? Thanks!

like image 952
Arthur Corenzan Avatar asked Aug 05 '17 21:08

Arthur Corenzan


1 Answers

As stated in the comments, problem here is once your interface has this signature:

type Greeter interface {
    Greet() Greeting
}

The any valid implementation must use exactly Greeting as the return type.

But, as the documentation shows, you don't need to give the interface a name:

https://golang.org/ref/spec#Interface_types

In order to be able to implement what you need, you might declare the interface directly in the return value, without giving it a name.

// Greeter greets with anything that has a String() method
type Greeter interface {
    Greet() interface{ String() string }
}

Then your Greet() function for Hello can do this:

// Hello greets by returning itself...
func (h *Hello) Greet() interface{ String() string } {
   return h
}

Find here a modified playground showing the working example:

https://play.golang.org/p/HteA_9jFd4

like image 78
eugenioy Avatar answered Oct 14 '22 08:10

eugenioy