I am trying to define a generic function in Go that accepts values that have certain fields, for example, ID int
. I have tried several approaches but none seems to work. Here is an example of what I have tried.
package main
import (
"fmt"
)
func Print[T IDer](s T) {
fmt.Print(s.ID)
}
func main() {
Print(Person{3, "Test"})
}
type IDer interface {
~struct{ ID int }
}
type Person struct {
ID int
Name string
}
type Store struct {
ID int
Domain string
}
And here is the playground link: https://gotipplay.golang.org/p/2I4RsUCwagF
In the example above, I want to guarantee every value passed to the Print
function has a property ID int
, which is also accessible in the function. Is there any way I can achieve this is Go without defining a method in an interface (e.g., GetID() int
)?
CodePudding user response:
Is there any way I can achieve this is Go without defining a method in an interface (e.g., GetID() int)?
No, you have to define the method in an interface.
The generics implementation in Go 1.18 doesn't have support for structural types, even though the original type parameters proposal suggests it would. I already wrote a bit more comprehensive explanation here.
Although, I think it's worth it to point out a misconception that can easily arise from your example: the meaning of the approximation ~T
(tilde-type) means "the set of types whose underlying type is T.
Now, when you write:
~struct{ ID int }
this means types whose underlying type is exactly struct{ ID int }
. No matter what, this does not include structs that have the field ID int
and something else. E.g. the underlying type of type Foo struct { ID int; Name string }
is struct { ID int; Name string }
, and not struct{ ID int }
, so that wouldn't satisfy the constraint anyway.
The current time param implementation doesn't have syntax to specify partial struct types. I recall a proposal to add field terms in interface constraints (along with type terms and methods), something on the line:
type IDer interface {
ID int
}
which would enable what you are trying to do without breaking the meaning of the tilde ~
. But this won't be included in Go 1.18.