In Go, how to define an interface using another interface?
Here is an example:
package main
import (
"fmt"
)
// Interfaces
type Message interface {
Read() string
}
type MessageReader interface {
ReceiveMessages([]Message)
}
// Structs
type SQSMessage struct {
Content string
}
type SQSMessageReader struct {
Name string
}
// Implements
func (reader *SQSMessageReader) ReceiveMessages([]SQSMessage) {
}
func (msg *SQSMessage) Read() string {
return msg.Content
}
// A function needs a reader interface
func FuncNeedsReader(MessageReader) {
fmt.Println("get reader")
}
func main() {
var reader SQSMessageReader
FuncNeedsReader(reader)
}
I got error:
./prog.go:40:17: cannot use reader (type SQSMessageReader) as type MessageReader in argument to FuncNeedsReader:
SQSMessageReader does not implement MessageReader (wrong type for ReceiveMessages method)
have ReceiveMessages([]SQSMessage)
want ReceiveMessages([]Message)
Do anyone know if this design is conflicting with Go's design?
I know we have "accept interfaces, return structs"
So I also tried https://play.golang.org/p/qdGaKRYAqw7, but still fail with similar error.
I see two problems here.
First:
You have defined your MessageReader interface as:
type MessageReader interface {
ReceiveMessages([]Message)
}
But you have defined your ReceiveMessages method on SQSMessageReader like this:
func (reader *SQSMessageReader) ReceiveMessages([]SQSMessage) {
}
Because it takes an []SQSMessage parameter rather than []Message, it does not implement the MessageReader interface. You would need to write:
func (reader *SQSMessageReader) ReceiveMessages([]Message) {
}
Second:
You have written:
func main() {
var reader SQSMessageReader
FuncNeedsReader(reader)
}
But ReceiveMessages has a pointer receiver (func (reader *SQSMessageReader) ReceiveMessages...), so you would need:
func main() {
var reader SQSMessageReader
FuncNeedsReader(&reader)
}
With these two changes, your code builds without errors.
Related
First time posting a question here, sorry if the format is wrong. Do let me know how I could improve my question asking.
package main
type smallerInterface interface {
Problem() smallerRet
}
type biggerInterface interface {
Problem() biggerRet
}
type smallerRet interface {
Wait() bool
}
type biggerRet interface {
Wait() bool
Error() error
}
type ret struct{}
type sample struct{}
func (ret) Wait() bool {
return true
}
func (ret) Error() error {
return nil
}
func (sample) Problem() biggerRet {
return ret{}
}
func main() {
var first biggerInterface = sample{}
var second smallerInterface = sample{}
}
Demo of the problem can be viewed here https://play.golang.org/p/l0xdO03bBy7
Basically, is there a way to reconcile both smallerInterface and biggerInterface so sample can be assigned to a variable of type smallerInterface?
Concretely I would like to use smallerInterface for mocking in internal testing and receive biggerInterface from an external library in producton. As such it would be preferable to keep the smallerRet interface so I can keep the mock return value interface small, with sample being the production return value.
Additionally, is there a name for this problem or concept?
Thanks in advance!
You can try embedding the interfaces so that the sample can be assigned to type smallerInterface. I recreated your code as follows :
package main
import "fmt"
type smallerInterface interface {
biggerInterface
}
type biggerInterface interface {
Problem() biggerRet
}
type smallerRet interface {
Wait() bool
}
type biggerRet interface {
Wait() bool
Error() error
}
type ret struct{}
type sample struct{}
func (ret) Wait() bool {
return true
}
func (ret) Error() error {
return nil
}
func (sample) Problem() biggerRet {
return ret{}
}
func main() {
var first biggerInterface = sample{}
var second smallerInterface = sample{}
fmt.Println(first)
fmt.Println(second)
}
Output:
{}
{}
How is actually methods in Go get dispatched if we use interface, static(compile time) or dynamic(run time). Let consider this code:
package main
import "fmt"
type ICat interface {
Meow()
Walk()
Run()
}
func NewCat(name string) ICat {
return &cat{
name:name,
}
}
type cat struct {
name string
}
func (c *cat) Meow() {
fmt.Print("Meowwwwwwwww")
}
func (c *cat) Walk() {
fmt.Print("Walk")
}
func (c *cat) Run() {
fmt.Print("Run")
}
type IAnimal interface{
DoSound()
}
type animal struct {
cat ICat
}
func New() IAnimal {
return &animal{
cat:NewCat("bobby"),
}
}
func (a *animal) DoSound() {
a.cat.Meow()
}
func main() {
i := New()
i.DoSound()
}
Go Playground: https://play.golang.org/p/RzipDT6FAC9
How actually those methods defined in those interface got dispatched?, I use this style of development to implement interface segregation and separation of concern between data and behaviour. My other concern is the perf. Some said it's statically dispatched at compile time, while other said it's dynamically dispatched at run time.
We cannot know at compile time what the dynamic type of an interface value will be, A call through an interface must use dynamic dispatch. Instead of a direct call, the compiler must generate code to obtain the address of the method from the type descriptor, then make an indirect call to that address.
I am trying to use google/wire for dependency injection.
When I use wire check command in terminal, it's shows no provider found for *my_go_app.Listener, output of injector.
wire.go
// +build wireinject
package main
import (
"fmt"
"github.com/google/wire"
)
type Speaker interface {
Say()
}
type HelloSpeaker struct {
word string
}
func NewHelloSpeaker() *HelloSpeaker {
return &HelloSpeaker{
word: "Hello, World!!",
}
}
func (s *HelloSpeaker) Say() {
fmt.Printf("%s", s.word)
}
type Listener interface {
WhatIListened()
}
type SimpleListener struct {
speaker *Speaker
}
func NewSimpleListener(speaker *Speaker) *SimpleListener {
return &SimpleListener{
speaker: speaker,
}
}
func (l *SimpleListener) WhatIListened() {
(*l.speaker).Say()
}
func InitializeListener() *Listener {
wire.Build(
NewHelloSpeaker,
NewSimpleListener,
)
return nil
}
main.go
package main
func main() {
listener := InitializeListener()
(*listener).WhatIListened()
}
What I tried is below.
NewSimpleListener return *Listener, but &SimpleListener not match *Listener.
Use wire.Bind, but same error message.
SimpleListener not implements Listener?
It seems that wire is not smart enough to do automatic conversion.
wire.go
...
//change type of argument of speaker from *Speaker to Speaker
//don't want to create a new conversion method
func NewSimpleListener(speaker Speaker) *SimpleListener
...
func InitializeListener() Listener {
wire.Build(
NewHelloSpeaker, //*HelloSpeaker, HelloSpeaker doesn't implement Speaker interfaces, conversion is needed in next step
wire.Bind(new(Speaker),new(*HelloSpeaker)), //this binding can provide Speaker, not *Speaker
NewSimpleListener, //scenario as NewHelloSpeaker
//provide Listener, an extra method is needed if *Listener is wanted.
wire.Bind(new(Listener), new(*SimpleListener)),
)
return nil
}
main.go
...
listener := InitializeListener()
listener.WhatIListened()
...
I want to use slacknotificationprovider in the NewNotifier function. How can I do it. Also I want send a string(config.Cfg.SlackWebHookURL) in newNotifier function. What should I do? Also please suggest me some material to get a deeper knowledge of struct and interface in golang.
I also want to know why ProviderType.Slack is not defined as I have mentioned it in ProviderType struct as of SlackNotificationProvider type? Thanks.
type SlackNotificationProvider struct {
SlackWebHookURL string
PostPayload PostPayload
}
type ProviderType struct {
Slack SlackNotificationProvider
Discord DiscordNotificationProvider
}
type Notifier interface {
SendNotification() error
}
func NewNotifier(providerType ProviderType) Notifier {
if providerType == ProviderType.Slack {
return SlackNotificationProvider{
SlackWebHookURL: SlackWebHookURL,
}
} else if providerType == ProviderType.Discord {
return DiscordNotificationProvider{
DiscordWebHookURL: SlackWebHookURL + "/slack",
}
}
return nil
}
slackNotifier := NewNotifier(config.Cfg.SlackWebHookURL)
Errors:
1. cannot use config.Cfg.SlackWebHookURL (type string) as type ProviderType in argument to NewNotifiergo
2. ProviderType.Slack undefined (type ProviderType has no method Slack)go
Golang is a strongly typed language, which means the arguments to your functions are defined and can't be different. Strings are strings and only strings, structs are structs and only structs. Interfaces are golang's way of saying "This can be any struct that has method(s) with the following signatures". So you can't pass a string as a ProviderType and none of your structs actually implement the interface method you've defined, so nothing would work as you've laid it out. To reorganize what you've got into something that might work:
const (
discordType = "discord"
slackType = "slack"
)
// This means this will match any struct that defines a method of
// SendNotification that takes no arguments and returns an error
type Notifier interface {
SendNotification() error
}
type SlackNotificationProvider struct {
WebHookURL string
}
// Adding this method means that it now matches the Notifier interface
func (s *SlackNotificationProvider) SendNotification() error {
// Do the work for slack here
}
type DiscordNotificationProvider struct {
WebHookURL string
}
// Adding this method means that it now matches the Notifier interface
func (s *DiscordNotificationProvider) SendNotification() error {
// Do the work for discord here
}
func NewNotifier(uri, typ string) Notifier {
switch typ {
case slackType:
return SlackNotificationProvider{
WebHookURL: uri,
}
case discordType:
return DiscordNotificationProvider{
WebHookURL: uri + "/slack",
}
}
return nil
}
// you'll need some way to figure out what type this is
// could be a parser or something, or you could just pass it
uri := config.Cfg.SlackWebHookURL
typ := getTypeOfWebhook(uri)
slackNotifier := NewNotifier(uri, typ)
As far as documentation to help with this, the "Go By Example" stuff is good, and I see other people have already linked that. That said, a struct with one method feels like it should be a function, which you can also define as a type to allow you to pass back a few things. Example:
type Foo func(string) string
func printer(f Foo, s string) {
fmt.Println(f(s))
}
func fnUpper(s string) string {
return strings.ToUpper(s)
}
func fnLower(s string) string {
return strings.ToLower(s)
}
func main() {
printer(fnUpper, "foo")
printer(fnLower, "BAR")
}
I am playing around with Go and found a problem I can't get around. Suppose I have my code like this:
// Imagine this is an external package for querying MySQL: I run a query
// and it gives me back a struct with a method "Result" to get the result
// as a string
// I can NOT modify this code, since it is an external package
package bar
type MySQL struct {}
func (m *MySQL) RunQuery() *MySQLResult {
return &MySQLResult{}
}
type MySQLResult struct {}
func (r *MySQLResult) Result() string {
return "foo"
}
I imported the package and started to use it:
// I created a little runner to help me
func run(m *bar.MySQL) string {
return m.RunQuery().Result()
}
func main() {
m := &bar.MySQL{}
fmt.Println(run(m)) // Prints "foo"
}
I really like my helper "run", but I'd like to make it more generous: I don't expect people to always pass me a MySQL client. It could be anything that has a "RunQuery" and "Result" method. So I try to use interfaces:
type AnyDB interface {
RunQuery() interface{ Result() string }
}
func run(m AnyDB) string {
return m.RunQuery().Result()
}
Sadly, this doesn't compile anymore. I get this error:
cannot use m (type *MySQL) as type AnyDB in argument to run:
*MySQL does not implement AnyDB (wrong type for RunQuery method)
have RunQuery() *MySQLResult
want RunQuery() interface { Result() string }
Is this not supported by Go, or am I doing something wrong?
RunQuery should return interface, otherwise you always have to deal with strong type.
AnyDB is not required, I added it for connivence.
AnyResult should be defined in bar package or being imported into it.
type AnyDB interface {
RunQuery() AnyResult
}
type MySQL struct{}
func (m *MySQL) RunQuery() AnyResult {
return &MySQLResult{}
}
type AnyResult interface {
Result() string
}
type MySQLResult struct{}
func (r *MySQLResult) Result() string {
return "foo"
}