In the following code, both options seem to allocate the same resource
func Allocate(v interface{}) error {
rv := reflect.ValueOf(v)
if rv.IsNil() {
return errors.New("Value of v is nil")
}
s0 := reflect.New(rv.Type().Elem())
s1 := reflect.New(rv.Elem().Type())
return errors.New(fmt.Sprintf("What's the diff? %v %v", s0, s1))
}
If there's no difference in this specific example, an example illustrating the difference will be great. Also what's the preferable option in this specific case when trying to allocate for an interface.
Edit: reflect.DeepEqual(s0, s1) returns false. I think rv.Elem().Type() has a problem dealing with zero values so maybe rv.Type().Elem() is preferred.
There is no difference if v
is a non-nil pointer type.
s := "hello"
rv := reflect.ValueOf(&s)
fmt.Println(rv.Type().Elem() == rv.Elem().Type()) // prints "true"
Here are some examples where rv.Type().Elem()
and rv.Elem().Type())
are different:
// nil pointer
var p *string
rv := reflect.ValueOf(p)
fmt.Println(rv.Type().Elem()) // prints "string"
fmt.Println(rv.Elem().Type()) // panic: call of reflect.Value.Type on zero Value
// interface value
var i interface{} = "hello"
rv := reflect.ValueOf(&i).Elem()
fmt.Println(rv.Type()) // prints "interface {}"
fmt.Println(rv.Elem().Type()) // prints "string"
fmt.Println(rv.Type().Elem()) // panic: Elem of invalid type
If rv.Type().Elem()
is used in Allocate
, then the nil check can be removed and the function will work with nil pointer values.
The call reflect.DeepEqual(s0, s1)
returns false because the ptr fields in the values are different. DeepEqual
compares unsafe pointers as simple values, not as pointers. This example might help explain what's going on:
v := "hello"
rv := reflect.ValueOf(&v)
s0 := reflect.New(rv.Type().Elem())
s1 := reflect.New(rv.Elem().Type())
s2 := reflect.New(rv.Type().Elem())
s3 := reflect.New(rv.Elem().Type())
fmt.Println(reflect.DeepEqual(s0, s1)) // prints "false"
fmt.Println(reflect.DeepEqual(s0, s2)) // prints "false"
fmt.Println(reflect.DeepEqual(s1, s3)) // prints "false"
fmt.Println(reflect.DeepEqual(s2, s3)) // prints "false"
fmt.Println(reflect.DeepEqual(s0.Interface(), s1.Interface())) // prints "true"
fmt.Println(reflect.DeepEqual(s0.Interface(), s2.Interface())) // prints "true"
fmt.Println(reflect.DeepEqual(s1.Interface(), s3.Interface())) // prints "true"
fmt.Println(reflect.DeepEqual(s2.Interface(), s3.Interface())) // prints "true"
As you can see, the reflect.Value comparisons are all false, even when created using the same sequence of calls.