0
votes

I am writing a unit test to check equality of struct that contains func.

Here are my test code. Go Palyround

When comparing, I used a func named GetFunctionName to get function's name for going.

func GetFunctionName(i interface{}) string {
    fmt.Printf("type in GetFunctionName: %v\n", reflect.TypeOf(reflect.ValueOf(i)))
    return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}

Also a compare function was made.

func SelectCompareStruct(got interface{}, want interface{}) {
    rvGot := reflect.ValueOf(got)
    rtGot := rvGot.Type()
    rvWant := reflect.ValueOf(want)
    rtWant := rvWant.Type()

    for i := 0; i < rtGot.NumField(); i++ {
        fieldGot := rtGot.Field(i)
        fieldWant := rtWant.Field(i)

        valueGot := rvGot.FieldByName(fieldGot.Name)
        valueWant := rvWant.FieldByName(fieldWant.Name)
        fmt.Printf("type in SelectCompareStruct: %v\n", reflect.TypeOf(reflect.ValueOf(valueGot)))

        // Works
        gotFuncNameInner := runtime.FuncForPC(valueGot.Pointer()).Name()
        wantFuncNameInner := runtime.FuncForPC(valueWant.Pointer()).Name()
        fmt.Printf("gotFuncNameInner:\n\t\t\t%v\nwantFuncNameInner:\n\t\t\t%v\n", gotFuncNameInner, wantFuncNameInner)

        // Does not work
        gotFuncName := GetFunctionName(valueGot)
        wantFuncName := GetFunctionName(valueWant)
        fmt.Printf("gotFuncName:\n\t%v\n wantFuncName:\n\t%v\n", gotFuncName, wantFuncName)
    }
}

You can see, when I write directly to get function's name, it works. However, it does not work when using a func instead. Although, both of which type that apply Pointer() method are reflect.Value type.

Yes, I can change input type of GetFunctionName to reflect.Value for working. That's not good for other use cases. I want to make a function for getting name for versatility. It will be beautiful to make input type interface{}.

Anyone have any idea why? And how to fix it?

1
valueGot is of type reflect.Value which is a struct. You are passing that to GetFunctionName which then passes that struct to reflect.ValueOf, which is why you get "panic: reflect: call of reflect.Value.Pointer on struct Value". - mkopriva
Thank you for your comment. That makes sense. Is there any way to workaround and keep the i as interface{} type? - tao4free
Yes, to get the underlying value represented by reflect.Value you can call the Interface() method. i.e. GetFunctionName(valueGot.Interface()) should work. - mkopriva
... but you need to export the filed, otherwise the Interface() method will panic. play.golang.org/p/zCv_F28CrfT - mkopriva
Thanks! That's perfect! - tao4free

1 Answers

1
votes

The problem is that you are calling reflect.Value on a reflect.Value. Fix by removing the extra call to reflect.Value.

func GetFunctionName(v reflect.Value) string {
    fmt.Printf("type in GetFunctionName: %v\n", v.Type())
    return runtime.FuncForPC(v.Pointer()).Name()
}

Run it on the playground.