I am writing some data structures to get my feet wet and learn about the Go language and am struggling with Go's lack of generics.
In my implementations I have chosen to force each user to implement an interface so my structures could refer to these objects abstractly but I don't love my solution because this is not verified at compile-time as you will see.
Comparer Interface
Each object that is held in a container must implement a Compare
function of the following signature (onerous if all you wanted to hold were raw types)
type Comparer interface {
Compare(Comparer) int
}
You could then have various elements that implement the interface like float64
or a custom struct:
float64
type number float64
func (n1 number) Compare(comparer Comparer) int {
n2, _ := comparer.(number)
if n1 > n2 {
return 1
} else if n1 < n2 {
return -1
} else {
return 0
}
}
Person
type Person struct {
Age int
}
func (p1 Person) Compare(comparer Comparer) int {
p2, _ := comparer.(Person)
if p1.Age > p2.Age {
return 1
} else if p1.Age < p2.Age {
return -1
} else {
return 0
}
}
And now I can compare some of these things:
func main() {
fmt.Println(number(2).Compare(number(4))) // -1
fmt.Println(Person{26}.Compare(Person{28})) // -1
fmt.Println(Person{26}.Compare(number(28))) // 1
}
The problem here is that I should not be able to compare a Person
and a number
. I realize that I can check the type at runtime but I would like to find either a) a compile-time way to verify the type or b) a different method to implement data structures generically.
Questions
- I know that one can do almost everything one might need with the built in data structures ... but how would someone make their own data structures without generics or runtime type checking?
- Since interface implementation in Go appears to use duck typing, how does Go enforce types at compile time?