gogenericsinterface

How to use a generic interface with generic methods in structs in go?


How would you define a method in an interface to be able to accommodate to accept a set of certain types of arguments based on some type related to the implementing struct? Take the below code as an example I would like to make the validate method to be generic, basically being able to accept the value argument to be only of one of the types - int, float64, string. But if I try to make use of generics here, then it simply won't work.. because go requires you to instantiate the generic type parameter at the time of defining the struct field. On the contrary, I would want to instantiate the type parameter on the time of instantiating the Payload's map index, so that the field is able to store all the different implementations (IntValidation, FloatValidation, StrValidation). But both of these things together don't seem to be feasible. So what would be the way to achieve this? Do we need to refactor and think about this in a different way?

type Validation[v Validateable] interface {
  validate(val v) error
}

type Validateable interface {
  int | float64 | string
}

/**
I would want the Payload Validation of map[string]Validation
To be able to accommodate the IntValidation, FloatValidation, StrValidation at the same time.. but after correcting the below specified error, I will only be able to use one of these at a time.. 
**/
type Request struct {
  Path string
  Payload map[string]Validation // Error: cannot use generic type without instantiation..
}

type IntValidation struct {
  Min int
  Max int
}

type FloatValidation struct {
  Min float64
  Max float64
}

type StrValidation struct {
  MinLength int
  MaxLength int
  Regex string
}

func (iv *IntValidation) validate(val any) error {
  return nil
}

func (fv *FloatValidation) validate(val any) error {
  return nil
}

func (sv *StrValidation) validate(val any) error {
  return nil
}


Solution

  • As @Volker remarked, you can't.

    From the Go FAQ: “Go permits a generic type to have methods, but, other than the receiver, the arguments to those methods cannot use parameterized types. [...] Instead of methods with type parameters, use top-level functions with type parameters, or add the type parameters to the receiver type.”

    Also from When To Use Generics: “Use reflection where appropriate”.

    In your case, since you come from strings from the web anyways, any + some reflection seems appropriate. You could try with top-level functions instead of methods, though.