2016-08-18 186 views
5

在下面的代碼,這兩個選項似乎分配相同的資源v.Type()。Elem()&v.Elem()。Type()之間的區別是什麼?

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()是首選。

Playground

+1

如果'v'是一個指針類型,我認爲沒有。 – Volker

+0

我也不這麼認爲,但肯定有一些差異,因爲reflect.DeepEqual(s0,s1)返回false – Sridhar

回答

5

有如果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 

如果rv.Type().Elem()Allocate使用,那麼零檢查可以被移除,並且功能將與零指針值工作。

呼叫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比較全是假的,即使使用電話的同一序列創建時。

+0

看起來像。只要rv.Elem()。IsValid(),兩者是相似的。 – Sridhar

+0

你認爲這是怎麼回事[這裏](https://play.golang.org/p/8HydwIfgP3)? – Sridhar

+0

@Sridhar看到更新的答案 –

相關問題