How to convert known type to pointer to type parameter in a switch?

I’m trying to write a function which converts a byte array of JSON string to another in accordance with the type parameter of the return value as the following rule:

  • map[string]interface{}: convert to map[string]interface{}
  • []byte: no conversion, return as is
  • struct: convert to the struc

My code is as follow:

func GetJsonData[T any](jsonByteArray []byte) (result *T, err error) {
    var buff T

    switch any(result).(type) { // https://appliedgo.com/blog/a-tip-and-a-trick-when-working-with-generics
    case *[]byte:
        result = &T(jsonByteArray)
    default:
        err = json.Unmarshal(jsonByteArray, &buff)
        result = &buff
    }

    return
}

This code occurs following type error at the point of cast the type of jsonByteArray to T as follows:

cannot convert jsonByteArray (variable of type []byte) to type T

How can I assign the pointer of this []byte type variable to the generic type return value?

>Solution :

Since T is constrained by any, you can’t directly convert. You have to assert that &jsonByteArray is really the same type as *T in that switch case:

func GetJsonData[T any](jsonByteArray []byte) (result *T, err error) {
    var buff T

    switch any(result).(type) {
    case *[]byte:
        result = any(&jsonByteArray).(*T)
    default:
        err = json.Unmarshal(jsonByteArray, &buff)
        result = &buff
    }

    return
}

This makes the compile error go away, however it isn’t particularly good design. If you need to specialize json.Unmarshal for only one type (*[]byte) you are better off changing the call sites instead of using a generic function.

I assume that your goal is to allow callers to get the byte slice as is, instead of unmarshalling. Then at call site you would call the function as

data := GetJsonData[[]byte](jsonByteArray)

This means that at that point you already know that jsonByteArray is a byte slice.

Then, there’s no reason to call the function. You can simply take the address of the argument: data := &jsonByteArray, and use json.Unmarshal everywhere else.

Leave a Reply