patterngoCritical
Why are interfaces needed in Golang?
Viewed 0 times
arewhygolanginterfacesneeded
Problem
In Golang, we use structs with receiver methods. everything is perfect up to here.
I'm not sure what interfaces are, however. We define methods in structs and if we want to implement a method on a struct, we write it anyway again under another struct.
This means that interfaces seem to be just method definitions, taking just extra unneeded space on our page.
Is there any example explaining why I need an interface?
I'm not sure what interfaces are, however. We define methods in structs and if we want to implement a method on a struct, we write it anyway again under another struct.
This means that interfaces seem to be just method definitions, taking just extra unneeded space on our page.
Is there any example explaining why I need an interface?
Solution
Interfaces are too big of a topic to give an all-depth answer here, but some things to make their use clear.
Interfaces are a tool. Whether you use them or not is up to you, but they can make code clearer, shorter, more readable, and they can provide a nice API between packages, or clients (users) and servers (providers).
Yes, you can create your own
We can already see some repetition in the code above: when making both
There is some similarity in both of the above types: both have a method
The interface contains only the signatures of the methods, but not their implementation.
Note that in Go a type implicitly implements an interface if its method set is a superset of the interface. There is no declaration of the intent. What does this mean? Our previous
Interfaces specify behavior. A type that implements an interface means that type has all the methods the interface "prescribes".
Since both implement
(That reflect part is only to get the type name, don't make much of it as of now.)
The important part is that we could handle both
Let's say you want to write other code that works with these types. A helper function:
Yes, the above function works with
Yes, you could write it to take an argument of
The solution? Yes, interfaces. Simply declare the function to take a value of an interface type which defines the behavior you want to do with it, and that's all:
You can call this function with a value of
Try these examples on the Go Playground.
Interfaces are a tool. Whether you use them or not is up to you, but they can make code clearer, shorter, more readable, and they can provide a nice API between packages, or clients (users) and servers (providers).
Yes, you can create your own
struct type, and you can "attach" methods to it, for example:type Cat struct{}
func (c Cat) Say() string { return "meow" }
type Dog struct{}
func (d Dog) Say() string { return "woof" }
func main() {
c := Cat{}
fmt.Println("Cat says:", c.Say())
d := Dog{}
fmt.Println("Dog says:", d.Say())
}We can already see some repetition in the code above: when making both
Cat and Dog say something. Can we handle both as the same kind of entity, as animal? Not really. Sure we could handle both as interface{}, but if we do so, we can't call their Say() method because a value of type interface{} does not define any methods.There is some similarity in both of the above types: both have a method
Say() with the same signature (parameters and result types). We can capture this with an interface:type Sayer interface {
Say() string
}The interface contains only the signatures of the methods, but not their implementation.
Note that in Go a type implicitly implements an interface if its method set is a superset of the interface. There is no declaration of the intent. What does this mean? Our previous
Cat and Dog types already implement this Sayer interface even though this interface definition didn't even exist when we wrote them earlier, and we didn't touch them to mark them or something. They just do.Interfaces specify behavior. A type that implements an interface means that type has all the methods the interface "prescribes".
Since both implement
Sayer, we can handle both as a value of Sayer, they have this in common. See how we can handle both in unity:animals := []Sayer{c, d}
for _, a := range animals {
fmt.Println(reflect.TypeOf(a).Name(), "says:", a.Say())
}(That reflect part is only to get the type name, don't make much of it as of now.)
The important part is that we could handle both
Cat and Dog as the same kind (an interface type), and work with them / use them. If you were quickly on to create additional types with a Say() method, they could line up beside Cat and Dog:type Horse struct{}
func (h Horse) Say() string { return "neigh" }
animals = append(animals, Horse{})
for _, a := range animals {
fmt.Println(reflect.TypeOf(a).Name(), "says:", a.Say())
}Let's say you want to write other code that works with these types. A helper function:
func MakeCatTalk(c Cat) {
fmt.Println("Cat says:", c.Say())
}Yes, the above function works with
Cat and with nothing else. If you'd want something similar, you'd have to write it for each type. Needless to say how bad this is.Yes, you could write it to take an argument of
interface{}, and use type assertion or type switches, which would reduce the number of helper functions, but still looks really ugly.The solution? Yes, interfaces. Simply declare the function to take a value of an interface type which defines the behavior you want to do with it, and that's all:
func MakeTalk(s Sayer) {
fmt.Println(reflect.TypeOf(s).Name(), "says:", s.Say())
}You can call this function with a value of
Cat, Dog, Horse or any other type not known until now, that has a Say() method. Cool.Try these examples on the Go Playground.
Code Snippets
type Cat struct{}
func (c Cat) Say() string { return "meow" }
type Dog struct{}
func (d Dog) Say() string { return "woof" }
func main() {
c := Cat{}
fmt.Println("Cat says:", c.Say())
d := Dog{}
fmt.Println("Dog says:", d.Say())
}type Sayer interface {
Say() string
}animals := []Sayer{c, d}
for _, a := range animals {
fmt.Println(reflect.TypeOf(a).Name(), "says:", a.Say())
}type Horse struct{}
func (h Horse) Say() string { return "neigh" }
animals = append(animals, Horse{})
for _, a := range animals {
fmt.Println(reflect.TypeOf(a).Name(), "says:", a.Say())
}func MakeCatTalk(c Cat) {
fmt.Println("Cat says:", c.Say())
}Context
Stack Overflow Q#39092925, score: 173
Revisions (0)
No revisions yet.