How do I use reflect.DeepEqual() to compare a pointer's value against the zero value of its type? - go

I need a generic function to check whether something is equal to its zero-value or not.
From this question, I was able to find a function that worked with value types. I modified it to support pointers:
func isZeroOfUnderlyingType(x interface{}) bool {
rawType := reflect.TypeOf(x)
//source is a pointer, convert to its value
if rawType.Kind() == reflect.Ptr {
rawType = rawType.Elem()
}
return reflect.DeepEqual(x, reflect.Zero(rawType).Interface())
}
Unfotunately, this didn't work for me when doing something like this:
type myStruct struct{}
isZeroOfUnderlyingType(myStruct{}) //Returns true (works)
isZeroOfUnderlyingType(&myStruct{}) //Returns false (doesn't) work
This is because &myStruct{} is a pointer and there is no way to dereference an interface{} inside the function. How do I compare the value of that pointer against the zero-value of its type?

reflect.Zero() returns a reflect.Value. reflect.New() returns a pointer to a zero value.
I updated the function to check the case where x is a pointer to something:
func isZeroOfUnderlyingType(x interface{}) bool {
rawType := reflect.TypeOf(x)
if rawType.Kind() == reflect.Ptr {
rawType = rawType.Elem()
return reflect.DeepEqual(x, reflect.New(rawType).Interface())
}
return reflect.DeepEqual(x, reflect.Zero(rawType).Interface())
}

Related

Is there a way to set a pointer struct field to a pointer pointing to the Zero value of that pointer type using reflect?

That was a mouthful of a title, let me explain more. Assuming I have a struct of all pointers (don't know of what type)
type A struct {
S *string
I *int
}
I want to write a function that takes a pointer to that struct and given a fieldName sets that field to a pointer to the Zero/empty value of that pointer. For example:
func setZeroForField(i any, fieldName string) {
// do stuff
}
a := A{}
setZeroForField(&a, "S")
setZeroForField(&a, "I")
// *a.S == ""
// *a.I == 0
Is there any way to do it using reflect? I know how to get the types of the fields of A but I can't use reflect.Indirect because it just returns a Zero value which in this case is a nil pointer, not the empty string or 0.
func setZeroForField(i any, fieldName string) {
rv := reflect.ValueOf(i).Elem()
fv := rv.FieldByName(fieldName)
fv.Set(reflect.New(fv.Type().Elem()))
}
https://go.dev/play/p/7clmztF5uaa

Ensuring a parameter must be pointer (or interface, which internally a pointer)

Sometimes we make a function that like C#'s out in the parameter, just like json.Unmarshal or any kind of unmarshal function.
How in Go compile time (instead of runtime) we can make sure that the variable that being passed is a pointer or an interface?
In runtime I can do something like this:
func mustStructPtr(f interface{}) {
v := reflect.ValueOf(f)
if v.Kind() != reflect.Ptr {
panic(fmt.Errorf("not a pointer: %T", f))
}
v = v.Elem() // dereference the pointer
if v.Kind() != reflect.Struct { // TODO: non null map or slice also ok
panic(fmt.Errorf("not struct; is %T", f))
}
}
How to enfoce this on compile time in Golang? so something like this are allowed
var myStruct MyStruct
myFunc(&myStruct) // ok, because pointer
myFunc(myStruct) // <-- not ok, because this cannot receive
var x interface{} = &mystruct
myFunc(x) // ok, because interface to pointer
x = myStruct
myFunc(x) // <-- not ok, because interface to non pointer
var y map[string]interface{}
myFunc(y) // ok, because map internally a pointer
var z = []myStruct{}
myFunc(&z) // ok, because a pointer
You can't really ensure that. If you really want a pointer I guess you could make your function generic and have it accept *T, but then you still don't know that T is a struct and it won't work with an interface.
You can catch this with linters (at least for json.Unmarshal) and otherwise, unit testing.
One of the approaches to increase type safety in your case would be to declare a new type and enforce the check on creation.
type PointerOrInterface struct {
val interface{}
}
func NewPointerOrInterface(val interface{}) PointerOrInterface {
// check
return PointerOrInterface{
val: val,
}
}

Return default value for generic type

How do you return nil for a generic type T?
func (list *mylist[T]) pop() T {
if list.first != nil {
data := list.first.data
list.first = list.first.next
return data
}
return nil
}
func (list *mylist[T]) getfirst() T {
if list.first != nil {
return list.first.data
}
return nil
}
I get the following compilation error:
cannot use nil as T value in return statement
You can't return nil for any type. If int is used as the type argument for T for example, returning nil makes no sense. nil is also not a valid value for structs.
What you may do–and what makes sense–is return the zero value for the type argument used for T. For example the zero value is nil for pointers, slices, it's the empty string for string and 0 for integer and floating point numbers.
How to return the zero value? Simply declare a variable of type T, and return it:
func getZero[T any]() T {
var result T
return result
}
Testing it:
i := getZero[int]()
fmt.Printf("%T %v\n", i, i)
s := getZero[string]()
fmt.Printf("%T %q\n", s, s)
p := getZero[image.Point]()
fmt.Printf("%T %v\n", p, p)
f := getZero[*float64]()
fmt.Printf("%T %v\n", f, f)
Which outputs (try it on the Go Playground):
int 0
string ""
image.Point (0,0)
*float64 <nil>
The *new(T) idiom
This has been suggested as the preferred option in golang-nuts. It is probably less readable but easier to find and replace if/when some zero-value builtin gets added to the language.
It also allows one-line assignments.
The new built-in allocates storage for a variable of any type and returns a pointer to it, so dereferencing *new(T) effectively yields the zero value for T. You can use a type parameter as the argument:
func Zero[T any]() T {
return *new(T)
}
In case T is comparable, this comes in handy to check if some variable is a zero value:
func IsZero[T comparable](v T) bool {
return v == *new(T)
}
var of type T
Straightforward and easier to read, though it always requires one line more:
func Zero[T any]() T {
var zero T
return zero
}
Named return types
If you don't want to explicitly declare a variable you can use named returns. Not everyone is fond of this syntax, though this might come in handy when your function body is more complex than this contrived example, or if you need to manipulate the value in a defer statement:
func Zero[T any]() (ret T) {
return
}
func main() {
fmt.Println(Zero[int]()) // 0
fmt.Println(Zero[map[string]int]()) // map[]
fmt.Println(Zero[chan chan uint64]()) // <nil>
}
It's not a chance that the syntax for named returns closely resembles that of var declarations.
Using your example:
func (list *mylist[T]) pop() (data T) {
if list.first != nil {
data = list.first.data
list.first = list.first.next
}
return
}
Return nil for non-nillable types
If you actually want to do this, as stated in your question, you can return *T explicitly.
This can be done when the type param T is constrained to something that excludes pointer types. In that case, you can declare the return type as *T and now you can return nil, which is the zero value of pointer types.
// constraint includes only non-pointer types
func getNilFor[T constraints.Integer]() *T {
return nil
}
func main() {
fmt.Println(reflect.TypeOf(getNilFor[int]())) // *int
fmt.Println(reflect.TypeOf(getNilFor[uint64]())) // *uint64
}
Let me state this again: this works best when T is NOT constrained to anything that admits pointer types, otherwise what you get is a pointer-to-pointer type:
// pay attention to this
func zero[T any]() *T {
return nil
}
func main() {
fmt.Println(reflect.TypeOf(zero[int]())) // *int, good
fmt.Println(reflect.TypeOf(zero[*int]())) // **int, maybe not what you want...
}
You can init a empty variable.
if l == 0 {
var empty T
return empty, errors.New("empty Stack")
}

How to get return type of a function

I'm writing higher order functions in Go, and am trying to figure out the return type of the inner function f.
As a simple example, let's say I want to return the default value of the return type of the inner function:
if f returns string, GetDefault(f) returns ""
if f returns []byte, GetDefault(f) return []byte{}
func GetDefault(func(interface{})) {
// How would I write this function?
}
Is it possible to write such a function in Go, without running f?
You can use reflection to get the type and initialize a default value.
func GetDefault(f interface{}) interface{} {
ft := reflect.TypeOf(f)
if ft.Kind() != reflect.Func {
panic("not a func")
}
out0 := ft.Out(0) // type of the 0th output value
return reflect.New(out0).Elem().Interface()
}
https://play.golang.org/p/BhevFvsut5z

interface{} variable to []interface{}

I have an interface{} variable and I know it's a pointer to slice:
func isPointerToSlice(val interface{}) bool {
value := reflect.ValueOf(val)
return value.Kind() == reflect.Ptr && value.Elem().Kind() == reflect.Slice
}
But I'm finding difficult to type cast it into an []interface{} variable:
if isPointerToSlice(val) {
slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{})
// 'worked' is false :(
}
This doesn't work. Any idea how can I solve this?
If you just want to convert a slice to []interface{} you can use something like this:
func sliceToIfaceSlice(val interface{}) []interface{} {
rf := reflect.Indirect(reflect.ValueOf(val)) // skip the pointer
if k := rf.Kind(); k != reflect.Slice && k != reflect.Array {
// panic("expected a slice or array")
return nil
}
out := make([]interface{}, rf.Len())
for i := range out {
out[i] = rf.Index(i).Interface()
}
return out
}
playground
You can simply use type assertion to obtain the value stored in an interface, e.g.
if isPointerToSlice(val) {
var result []interface{}
result = *val.(*[]interface{})
fmt.Println(result)
} else {
fmt.Println("Not *[]interface{}")
}
The type of the value stored in the interface as you claim is pointer to []interface{}, which is *[]interface{}. The result of the type assertion will be a pointer, just dereference it to get the slice []interface{}.
Using short variable declaration:
result := *val.(*[]interface{}) // type of result is []interface{}
Try it on the Go Playground.
Also your attempt also works:
slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{})
fmt.Println(slice, worked)
Here's the edited the Playground example which proves your solution works.
But using reflection is unnecessary (as it can be done with type assertion).
Also note that *[]interface{} and *[]someOtherType are 2 different types and you can't obtain a value of *[]interface{} if there is something else in val.
Icza's answer is great and will work especially if you can't know for sure you are getting an interface slice, however if you don't want to bother with the reflect package at all and want to keep imported code low, you can use type switching to obtain the same functionality using only built-in methods.
Using this method, you can shorten your code to just:
package main
import (
"fmt"
)
func main() {
s := []interface{}{"one", 2}
p := &s
do(p)
}
func do(val interface{}) {
switch val.(type){
case *[]interface{}:
var result []interface{}
result = *val.(*[]interface{})
fmt.Println(result)
}
}
Playground: http://play.golang.org/p/DT_hb8JcVt
The downside is if you don't know the exact type of slice you are receiving beforehand, then this will not work unless you list all possible types for handling and assertion.

Resources