Странное поведение для указателя интерфейса - PullRequest
0 голосов
/ 25 ноября 2018

Я написал 3 аналогичные функции, чтобы выяснить странное поведение отражения указателя Go.

package main

import (
    "reflect"
    "fmt"
)

var i interface{} = struct {}{}     // i is an interface which points to a struct
var ptr *interface{} = &i           // ptr is i's pointer

func f(x interface{}) {             // print x's underlying value
    fmt.Println(reflect.ValueOf(x).Elem())
}

func main1() {  // f is asking for interface? OK, I'll use the struct's interface
    structValue := reflect.ValueOf(ptr).Elem().Elem().Interface()
    f(structValue)
}

func main2() {  // Error? Let me try the struct's pointer
    structPtr := reflect.ValueOf(ptr).Elem().Interface()
    f(structPtr)
}

func main3() {  // Why this one could succeed after New() ?
    typ := reflect.ValueOf(ptr).Elem().Elem().Type()
    newPtr := reflect.New(typ).Elem().Addr().Interface()
    f(newPtr)
}

func main() {
    //main1()   // panic: reflect: call of reflect.Value.Elem on struct Value
    //main2()   // panic: reflect: call of reflect.Value.Elem on struct Value
    main3()     // OK. WHY???
}

Работает только main3, остальные 2 будут паниковать.Зачем?Ключевое отличие 3 в том, что он создает новое значение.

Что касается main2, я думаю, ValueOf().Elem().Interface() уже реконструировал интерфейс, который указывает на struct{}{}, просто не понимаю, почему он потерпит неудачу.

1 Ответ

0 голосов
/ 25 ноября 2018

Значение, возвращаемое из refle.ValueOf содержит конкретное значение, сохраненное в аргументе.Если аргумент равен nil, возвращается нулевое отражение. Значение:.

Другими словами, отражающее значение и интерфейс, переданные в отражение. Значение имеют одно и то же значение.

Функции main1 и main2 будут работать так, как я думаю, вы ожидаете, если вы f измените на:

func f(x interface{}) {             // print x's underlying value
    fmt.Println(reflect.ValueOf(x))
}

Аргументом f в main3 является *struct{}.Функция f разыменовывает указатель (с вызовом Elem ()) и печатает значение отражения для struct{}.

. Единственное, что может сбить с толку, это то, что reflect.ValueOf(ptr).Elem().Elem().Interface() и reflect.ValueOf(ptr).Elem().Interface() возвращаютинтерфейс с тем же конкретным значением.

Выражение reflect.ValueOf(ptr).Elem() является значением отражения, соответствующим i.Вызов Interface() для этого значения возвращает интерфейс с конкретным значением в i.

Выражение reflect.ValueOf(ptr).Elem().Elem() является значением отражения, соответствующим конкретному значению i.Вызов Interface() для этого значения возвращает интерфейс, содержащий это конкретное значение.

...