vendredi 8 janvier 2021

go: return a generic empty object clone using reflection

I need an empty copy of an object in go, without knowing it's type directly. This code will succesfully return an object as a pointer to the type. However, I don't seem to be able to just get the pointer value after that.

Trying to get this right, but getting hung up on being a value type. I can make the pointer thing work for my situation, but want to understand why it seems so hard to get the value.


package watch

import "reflect"

type TestStruct struct {
    Name string
    Data string
}

func TestClone(t *testing.T) {
    var obj TestStruct
    obj.Name = "test case"
    gotPtr := cloneEmptyObject(obj)
    got := *gotPtr.(*TestStruct)
    print(got.Name)
}

// This works but returns me a pointer, and I can cast if I explicitly have the type
func cloneEmptyObject(obj interface{}) interface{} {

    vesselObjPtr := reflect.New(reflect.TypeOf(obj)).Interface()
    // want to do the equivalent of this without explicitly having type TestStruct:
    // return *vesselObjPtr.(*TestStruct) 
    return vesselObjPtr
}

func TestClone2(t *testing.T) {
    var obj TestStruct
    obj.Name = "test case"
    got := cloneEmptyObject2(obj)
    b:= got.(TestStruct) //This fails and causes a panic
    print(b.Name)
}

//want this where I don't explicitly need the Type to get the value
func cloneEmptyObject2(obj interface{}) interface{} {

    vesselObjPtr := reflect.New(reflect.TypeOf(obj))
    // return *vesselObjPtr //invalid indirect of vesselObjPtr (type "reflect".Value)
    vesselObj := reflect.Indirect(vesselObjPtr)
    return vesselObj // want this to be TestStruct, but it is a reflect.Value, and can't be cast
}

func TestClone3(t *testing.T) {
    var obj TestStruct
    obj.Name = "test case"
    got := cloneEmptyObject3(obj)
    b:= got.(TestStruct)
    print(b.Name)
}

func cloneEmptyObject3(obj interface{}) interface{} {

    return reflect.Zero(reflect.TypeOf(obj))
}

func TestClone4(t *testing.T) {
    var obj TestStruct
    obj.Name = "test case"
    got := cloneEmptyObject4(obj)
    b:= got.(TestStruct)
    print(b.Name)
}

func cloneEmptyObject4(obj interface{}) interface{} {

    return reflect.New(reflect.TypeOf(obj)).Elem()
}
=== RUN   TestClone
--- PASS: TestClone (0.00s)
=== RUN   TestClone2
--- FAIL: TestClone2 (0.00s)
panic: interface conversion: interface {} is reflect.Value, not watch.TestStruct [recovered]
    panic: interface conversion: interface {} is reflect.Value, not watch.TestStruct
=== RUN   TestClone3
--- FAIL: TestClone3 (0.00s)
panic: interface conversion: interface {} is reflect.Value, not watch.TestStruct [recovered]

=== RUN   TestClone4
--- FAIL: TestClone4 (0.00s)
panic: interface conversion: interface {} is reflect.Value, not watch.TestStruct [recovered]
    panic: interface conversion: interface {} is reflect.Value, not watch.TestStruct







Aucun commentaire:

Enregistrer un commentaire