Home > Enterprise >  How to change struct tags by generics
How to change struct tags by generics

Time:09-28

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"`
}

CodePudding user response:

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.

CodePudding user response:

It's imposible!

For your case you can redesign your architecture

  • Related