Reputation: 8773
I am trying to understand how interfaces work in Go.
Let's say I have 2 structs:
package "Shape"
type Square struct {
edgesCount int
}
type Triangle struct {
edgesCount int
}
Now I create a Shape
interface:
type Shape interface {
}
Why can't I specify that the Shape
interface has an egdesCount
property? Are interfaces only supposed to regroup methods?
Another problem I face is sharing function. Isn't possible to come up with something like this:
func New() *Shape {
s:=new(Shape)
s.edgesCount = 0
return s
}
This would be much better than having to rewrite the exact same code:
func New() *Square {
s:=new(Square)
s.edgesCount = 0
return s
}
func New() *Triangle {
s:=new(Triangle)
s.edgesCount = 0
return s
}
(which also poses problem as I cannot redeclare my New
function...)
Many thanks for your help
Upvotes: 0
Views: 233
Reputation: 391
Interface only group methods, as their purpose is to define behavior, very much like in other languages (see Java Interfaces, for example).
What you are looking for is something like code inheritance, which doesn't exist in Go. BUT, you can get something similar with struct embedding:
Go does not provide the typical, type-driven notion of subclassing, but it does have the ability to “borrow” pieces of an implementation by embedding types within a struct or interface.
So, you can get what you want by doing the following (play link):
type Shape struct {
edgeCount int
}
func (s Shape) EdgeCount() int {
return s.edgeCount
}
type Square struct {
Shape
}
type Triangle struct {
Shape
}
func main() {
sq := Square{Shape{edgeCount: 4}}
tr := Square{Shape{edgeCount: 3}}
fmt.Println(sq.EdgeCount())
fmt.Println(tr.EdgeCount())
}
Upvotes: 0
Reputation: 1323115
What you are referring to isn't interface (which allows to pass an object as that interface, simply because the object is a receiver for all the interface method).
Here, an empty interface{}' Shape
would be satisfied by any type, which isn't useful here.
It is more about type embedding (using an anonymous type structure for instance):
That would promote the common field edgesCount
to both struct.
As the spec mentions:
A field or method
f
of an anonymous field in astruct x
is called promoted ifx.f
is a legal selector that denotes that field or methodf
.
See this example:
type Shape struct {
edgesCount int
}
type Square struct {
Shape
}
type Triangle struct {
Shape
}
func NewSquare() *Square {
return &Square{
Shape{edgesCount: 4},
}
}
func NewTriangle() *Triangle {
return &Triangle{
Shape{edgesCount: 3},
}
}
func main() {
fmt.Printf("Square %+v\n", NewSquare())
fmt.Printf("Triangle %+v\n", NewTriangle())
}
Output:
Square &{Shape:{edgesCount:4}}
Triangle &{Shape:{edgesCount:3}}
Upvotes: 3
Reputation: 2579
Go isn't an object oriented language, and those fields are internal fields since they start with lower case letters. Instead, try something like this:
type Shape interface {
EdgeCount() int
}
type Square struct {
edgesCount int
}
func (s Square) EdgeCount() int {
return s.edgesCount
}
type Triangle struct {
edgesCount int
}
func (t Triangle) EdgeCount() int {
return t.edgesCount
}
Now you can do things using the EdgeCount function on either type of object since they both implement the Shape interface.
func IsItSquare(s Shape) bool {
// If it has 4 sides, maybe
return s.EdgeCount == 4
}
But you will still need to create the different types of shapes with independent New functions, or just by declaring them literally.
// Obviously a contrived example
s := Triangle{edgesCount: 3}
Upvotes: 2