Any type and implementing generic list in go programming language
I'm trying a little of go programming language.
I'm a excited about the simplicity of the Go, but after playing with it I met some troubles.
1 . I know that Go doesn't support generics and inheritance. Is there any way to implement generic list?
I thinking about using:
开发者_运维百科type Any interface { }
but how can I check if the value is NULL.
I'm looking for some equivalent implementation to Cstruct List {
List* tail;
void* head;
}
Or using algebraic datatype:
data List a = Nil | Cons a (List a)
2 . More advanced requirement would be to make some container for objects with a field of a particular type?
For example in Scala programming language I can type:
val List[Animal { type SuitableFood = Grass} ]
to get a List
of Animals
, which have a member type SuitableFood
which is Grass
You can have a list of elements of type interface{}
. You can put any elements in, and when you get it out, you have to cast back to the type you want. This is like what you're doing void *
in your C example; and also like lists in Java before Generics, and in Objective-C, which doesn't have generics. All the containers in the Go library do this.
Without generics, there is no compile-time checking of the element types.
If you really wanted, you could implement run-time checks for element type, by using reflection to get the element types and checking them against the expected type. However, this is probably overkill.
I know that Go doesn't support generics [...]
It does as of Go 1.18. I expect the standard library to eventually add generic containers along the current container/list
package so you don't have to reinvent the wheel.
Anyway as a thought exercise you could copy the standard list.List
and add type parameters yourself:
type Element[T any] struct {
next, prev *Element[T]
list *List[T]
Value T
}
type List[T any] struct {
root Element[T]
len int
}
// simplified constructor
func New[T any]() *List[T] {
l := new(List[T])
l.root.next = &l.root
l.root.prev = &l.root
l.len = 0
return l
}
As you can see Element
struct can have a field of type Element
, but the type params must be the same ones and in the same order (source).
make some container for objects with a field of a particular type?
You can do this by replacing the constraint any
with an interface constraint that specified the method you want, for example:
type Animal interface {
SuitableFood() string
}
type Element[T Animal] struct {
// ...
}
and this constrains the type parameter to those that implement the Animal
interface.
What you can not do is constrain the type param to have a particular field1. If you must force T
to have specific values, you could instead add a more specific method to the interface constraint, e.g. SuitableFoodGrass()
but that's a leaky abstraction. Interfaces model behavior, and you should stick to that principle.
1: Technically you can, using a type constraint with a struct, but it wouldn't be very useful.
精彩评论