Reputation: 13632
This question is about the cleanest way to "inherit" interface implementations in golang. I understand Go does not have inheritance; this question is about how people achieve it otherwise, hence the quotes around inheritance.
Let's say theres a standard library interface defined, for example container/heap
: https://golang.org/pkg/container/heap/#Interface
Lets say there's a .go
file called pq.go
that implements that interface:
//pq.go
import ("container/heap")
type PriorityQueue []*Vertex
func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {
...
}
func (pq PriorityQueue) Swap(i, j int) {
...
}
func (pq *PriorityQueue) Push(x interface{}) {
...
}
func (pq *PriorityQueue) Pop() interface{} {
...
}
Now let's say I just want a Tiny variant on this, called MaxPQ
, in maxpq.go
, for where I want to override a single implementation detail of pq.go
, e.g., override Less(..)
. How do I achieve this without literally copying the last file over, changing the type name, and changing the implementation of the single function, e.g., less
?
Meaning, is there a way to make a new implementation of an interface that is very similar to another?
Doing this, literally copying it over, seems drastic and changes would need to be made in multiple places:
//maxpq.go
import ("container/heap")
type MaxPriorityQueue []*Vertex
func (pq MaxPriorityQueue) Len() int { return len(pq) }
func (pq MaxPriorityQueue) Less(i, j int) bool {
...
}
func (pq MaxPriorityQueue) Swap(i, j int) {
...
}
func (pq *MaxPriorityQueue) Push(x interface{}) {
...
}
func (pq *MaxPriorityQueue) Pop() interface{} {
...
}
Upvotes: 0
Views: 417
Reputation: 752
You can try something like this using composition.
type iTemp interface {
func1()
func2()
}
type base struct {
}
func (base) func1() {
fmt.Println("base func1")
}
func (base) func2() {
fmt.Println("base func2")
}
type child struct {
base
}
func (child) func1() {
fmt.Println("child func1")
}
func main(){
printMessage(base{})
printMessage(child{})
}
func printMessage(t iTemp) {
t.func1()
t.func2()
}
output:
base func1
base func2
child func1
base func2
Here in child struct you are providing a new implementation of func1 function of base class, but you still have access to base class implementation, you can still call it using child{}.base.func1()
Upvotes: 0
Reputation: 51512
There are multiple ways you can do this.
You can define a new type based on the original type, and delegate all methods:
type OriginalType struct {...}
func (o OriginalType) F() {...}
type NewType OriginalType
func (n NewType) F() { OriginalType(n).F() }
With this, you need to redefine all methods of the original type, as the NewType does not "inherit" the methods of the OriginalType.
You can embed:
type NewType struct {
OldType
}
Now you have a NewType.F() function, but it will operate on the OldType portion of the NewType. If you want to redeclare that, you can:
func (n NewType) F() {
n.OldType.F();
// Do more stuff
}
This will work like inheritance if you pass either instance through an interface. That is:
type IntF interface {
F()
}
func f(v IntF) {
v.F()
}
If you pass a NewType, then NewType.F will be called.
However, you have to pass an interface, you cannot pass the embedded struct to get the behavior of the enclosing object:
func f(v OriginalType) {
v.F()
}
func main() {
n:=NewType()
// f(n) Won't work
f(n.OriginalType)
Above, only the OriginalType part of n is sent to the function f, and OriginalType.F will be called.
Upvotes: 1