如何通过泛型更改结构标签

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

How to change struct tags by generics

问题

我需要创建一个带有动态标签的泛型结构体。

例如,我们有一个带有泛型的结构体 Phone[T] 和一个简单的结构体 Company

所以,Phone 可以属于 Company,这意味着我们的类型将是 Phone[Company]

type Company struct{}

type Phone[T any] struct{
   number string `json:"phone_number"`
}

让我们创建一个新的变量 Phone[Company]

phone1 := Phone[Company]{
   number: "+18888888888"
}

序列化后的 phone1 的输出结果为

{
   "phone_number": "+18888888888"
}

问题

如何动态设置结构体 Phone[T] 类型字段的标签,以接收类似于 company_phone_number 而不是 phone_number 的 JSON 数据?

如何在 Golang 的标签中使用泛型类型?

例如:

type Phone[T any] struct{
   number string `json:"${T 或 T 类型的复制品名称}_phone_number"`
}
英文:

I need to create struct with generics with dynamic tags

> e.g. We have one struct with generics Phone[T] and simple struct Company

So Phone can belongs to Company and that means our type would be Phone[Company]

type Company struct{}

type Phone[T any] struct{
   number string `json:"phone_number"`
}

Lets create new variable Phone[Company]

phone1 := Phone[Company]{
   number: "+18888888888"
}

Output of serialized phone1 is

{
   "phone_number": "+18888888888"
}

Question

How to set struct Phone[T] type field tags dynamically to receive json like company_phone_number instead of phone_number?

How can i use generic types in golang tags?

e.g.

type Phone[T any] struct{
   number string `json:"${T or replica name of T type e.t.c}_phone_number"`
}

答案1

得分: 4

你只能通过使用反射在运行时重新构建你的结构体来实现这一点。有一个专门的包可以做到这一点(我没有尝试过)这里

但是,我建议你为结构体编写一个自定义的MarshalJSON方法,根据变量的类型处理不同的情况。

package main

import (
	"encoding/json"
	"errors"
	"fmt"
)

type Phone[T any] struct {
	variableType T
	Number       string
}

func (p Phone[T]) MarshalJSON() ([]byte, error) {
	switch any(p.variableType).(type) {
	case Company:
		return json.Marshal(&struct {
			Number string `json:"company_phone_number"`
		}{
			Number: p.Number,
		})
	case Company2:
		return json.Marshal(&struct {
			Number string `json:"company2_phone_number"`
		}{
			Number: p.Number,
		})
	}
	return []byte{}, errors.New("Invalid type")
}

type Company struct {
}

type Company2 struct {
}

func main() {
	p := Phone[Company]{
		Number: "123",
	}

	p2 := Phone[Company2]{
		Number: "321",
	}

	data1, _ := json.Marshal(p)
	data2, _ := json.Marshal(p2)
	fmt.Println(p, string(data1))
	fmt.Println(p2, string(data2))
}

Playground

如果你想避免使用switch语句,你可以使用reflect.TypeOf(p.variableType).Name()来获取变量的类型,但是你需要编写一个自定义的JSON marshaler来表示带有自定义JSON标签的字节切片。

英文:

You can do it only if you rebuild your struct on-the-fly with reflect. There is a package for this (I didn't try it) here.

But instead I recommend you to write a custom MarshalJSON method for the struct which handles the cases based on the type of the variable.

package main

import (
	"encoding/json"
	"errors"
	"fmt"
)

type Phone[T any] struct {
	variableType T
	Number       string
}

func (p Phone[T]) MarshalJSON() ([]byte, error) {
	switch any(p.variableType).(type) {
	case Company:
		return json.Marshal(&struct {
			Number string `json:"company_phone_number"`
		}{
			Number: p.Number,
		})
	case Company2:
		return json.Marshal(&struct {
			Number string `json:"company2_phone_number"`
		}{
			Number: p.Number,
		})
	}
	return []byte{}, errors.New("Invalid type")
}

type Company struct {
}

type Company2 struct {
}

func main() {
	p := Phone[Company]{
		Number: "123",
	}

	p2 := Phone[Company2]{
		Number: "321",
	}

	data1, _ := json.Marshal(p)
	data2, _ := json.Marshal(p2)
	fmt.Println(p, string(data1))
	fmt.Println(p2, string(data2))
}

Playground

If you want to avoid the switch you can get the variable type with reflect.TypeOf(p.variableType).Name() but then you have to write a custom JSON marshaler to represent the byte slice with the custom json tags.

答案2

得分: 0

这是要翻译的内容:

这是不可能的!

对于你的情况,你可以重新设计你的架构。

英文:

It's imposible!

For your case you can redesign your architecture

huangapple
  • 本文由 发表于 2022年9月27日 15:29:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/73863850.html
匿名

发表评论

匿名网友

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

确定