如何将已知类型转换为类型参数的指针在switch语句中?

huangapple go评论82阅读模式
英文:

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

问题

我正在尝试编写一个函数,根据返回值的type参数,将一个JSON字符串的字节数组转换为另一个字节数组,转换规则如下:

  • map[string]interface{}:转换为map[string]interface{}
  • []byte:不进行转换,原样返回
  • struct:转换为struct

我的代码如下:

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

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

    return
}

在将jsonByteArray的类型转换为T的类型时,代码出现以下类型错误

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

我该如何将这个**[]byte**类型变量的指针赋值给泛型类型的返回值?

英文:

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?

答案1

得分: 5

由于T受到any的限制,你不能直接转换。你必须断言&jsonByteArray在switch case中确实是与*T相同的类型:

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
}

这样可以消除编译错误,但这并不是特别好的设计。如果你只需要为一个类型(*[]byte)专门定制json.Unmarshal,最好是改变调用点而不是使用通用函数。

我假设你的目标是允许调用者获取字节切片而不是解组。那么在调用点,你可以这样调用函数:

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

这意味着在那一点上你已经知道jsonByteArray是一个字节切片。

然后,没有理由调用该函数。你可以简单地取参数的地址:data := &jsonByteArray,并在其他地方使用json.Unmarshal

英文:

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.

huangapple
  • 本文由 发表于 2023年5月26日 08:12:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76336911.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定