1

I am working with a third-party function, with a generic of type any. That function returns an object of the type passed to it, and my own code works against that returned thing.

I'm trying to write my own generic function, which takes in a generic of type HasID, and then passes that to the third-party function. However, when I attempt to access the ID field of the return value from the third-party function, I get an error.

What do I need to do in order to type this properly?

type HasID struct {
    ID string `json:"id"`
}

func ThirdPartyFunc[T any]() T {
  // do some stuff
  return someThing // of type T
}

func MyFunc[U HasID]() {
  thingWithID := ThirdPartyFunc[U]()
  fmt.Println(thingWithID.ID) // undefined (type U has no field or method ID)
}
Kevin Whitaker
  • 12,435
  • 12
  • 51
  • 89
  • 2
    Why not pass `HasID` as the type argument instead of `U`? For example: https://go.dev/play/p/eIVXjMmxB9_g – mkopriva Aug 17 '23 at 17:44
  • Why have a type parameter of `[U HasID]` with a single concrete type in the first place? If you are hard-coding the type, just put that as the type parameter for `ThirdPartyFunc`. Not everything needs to be generic, but is there another reason for this? – JimB Aug 17 '23 at 18:20
  • I have multiple different types which all have an `ID` parameter, that I'd like to be able to use with this function. – Kevin Whitaker Aug 18 '23 at 13:16

1 Answers1

4

I agree with the comment from @mkopriva, but I think it's probably because you "can't" define fields on Constraints, so you can't access these fields in your type argument.

The Go compiler does not support accessing a struct field x.f where x is of type parameter type even if all types in the type parameter's type set have a field f. We may remove this restriction in Go 1.19.

(Well it probably wasn't changed in Go 1.19 lol)

For simplicity, it's like you will do:

type HasID struct {
    ID string `json:"id"`
}

func MyFunc[U HasID](hasID U) {
    fmt.Println(hasID.ID) // hasID.ID undefined (type U has no field or method ID)

}

https://go.dev/play/p/oRvfFfHrOOL

But if you define it as an interface, you will have access to its methods:

type HasID interface {
    ID() string
}

func MyFunc[U HasID](hasID U) {
    fmt.Println(hasID.ID()) // compiles V
}

https://go.dev/play/p/M1E7zTNlVxr

For dealing with structs, you need to do some type conversion:

type HasID struct {
    ID string `json:"id"`
}

func MyFunc[U HasID](hasID U) {
    thingWithID := HasID(hasID)
    fmt.Println(thingWithID.ID)
}

P.S - there is an open issue on that from 02/2022 - https://github.com/golang/go/issues/51259

P.S - oh and also I just found that... - How can I access a struct field with generics (type T has no field or method)?

oren
  • 3,159
  • 18
  • 33