v.Type().Elem()和v.Elem().Type()有什么区别?它们涉及到IT技术。

6
在下面的代码中,两个选项似乎都分配相同的资源。
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))
}

如果在这个具体的例子中没有区别,那么一个说明区别的示例将是很好的。此外,在尝试为接口分配时,在这种具体情况下,哪种选项更可取。
编辑:reflect.DeepEqual(s0, s1) 返回false。我认为rv.Elem().Type()在处理零值时存在问题,因此可能更喜欢rv.Type().Elem()。 操场

1
我认为如果v是指针类型,则没有。 - Volker
我之前也没想到会这样,但肯定存在某些差异,因为 reflect.DeepEqual(s0,s1) 返回了 false。 - Sridhar
1个回答

8
如果v是非空指针类型,则没有区别。
s := "hello"
rv := reflect.ValueOf(&s)
fmt.Println(rv.Type().Elem() == rv.Elem().Type()) // prints "true"

以下是一些示例,其中rv.Type().Elem()rv.Elem().Type())不同:
// 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

如果在Allocate中使用rv.Type().Elem(),则可以删除nil检查,并且该函数将适用于nil指针值。
调用reflect.DeepEqual(s0, s1)返回false,因为值中的ptr fields不同。 DeepEqual将不安全指针视为简单值而不是指针进行比较。这个例子可能有助于解释正在发生的事情:
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"

正如您所看到的,即使使用相同的调用序列创建,reflect.Value比较也全部为false。

看起来是这样的。只要rv.Elem().IsValid(),两者就相似。 - Sridhar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接