'What is the dereference operator of a type in Go generics?
When doing generics, one can create a pointer type from any type, see Pointer Method Example section in Types Parameter Proposal. Example:
type Pointer[T any] interface {
*T // non-interface type constraint element
// ... more constraints ...
}
How does one do the opposite, declare a dereference of a type ? Something like:
type Deref[T any] interface {
???T // If T=="*int", this would refer to "int"
...
}
Thanks!
Solution 1:[1]
You can only dereference pointer vaues, but not types. *T is not dereferencing the T type, *T is a type literal, composing a pointer type whose base type will be T.
The compiler only allows operations on values of type parameters that are allowed on the constrained types.
Using any, all types will be allowed, even non-pointer types, whose values cannot be dereferenced.
To dereference a value, it must be a pointer. One way is to specify a parameter to be of type *T like in this example:
func deref[T any](p *T) T {
return *p
}
T can be of any type, but *T will surely be a pointer type, whose values can be dereferenced. Testing it:
p := &image.Point{1, 2}
x := deref(p)
log.Printf("%T %v\n", x, x)
p := new(int)
*p = 3
x := deref(p)
log.Printf("%T %v\n", x, x)
Output will be:
2009/11/10 23:00:00 image.Point (1,2)
2009/11/10 23:00:00 int 3
Another option is to use a constraint that allows only pointer types, for example only *int:
func deref2[T interface{ *int }](p T) {
log.Printf("%T %v\n", *p, *p)
}
Testing it:
p := new(int)
*p = 4
deref2(p)
Output:
2009/11/10 23:00:00 int 4
Although using generics here has no use, you could just substitute T with *int, without type parameters.
Try the examples on the Go Playground.
Solution 2:[2]
There is no such thing as a "dereference of a type".
Pointer types are composite types, i.e. you need a base type to begin with. You can't go the other way around.
What to do instead
If you want to force non-pointer types in a constraint, specify the non-pointer types:
// will disallow *int
type NonPointerInt interface {
~int
}
Notes
the above is not generalizable to any
T. Using~Tin a type set whereTis a type parameter is explicitly disallowed: "Using ~T is not permitted if T is a type parameter or if T is an interface type".you may add more related types to the union, e.g.
~int | ~int32 | ~int64etc. With this you're getting closer toconstraints.Signedor similar constraints offered by the standard libyou may add more (partially) unrelated types, e.g.
~int | ?~stringbut then you're reducing the operations you can do on values with such constraint.
About the letter of your question, a pointer type *T is useful to achieve (arbitrary levels of) indirection from a base type, and it has a precise practical meaning, tied to the concept of a pointer as the address of a memory location. It's unclear what a hypothetical "dereference type" would be in practical terms, without using a circular definition.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 |
