Using any and generic in struct

I’ve the below code:

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
)

type Number interface {
	int64 | float64
}

type SKUcard[number Number] struct {
	BarCode, SKUCode                                                              any
	VendorCode, RegistrationDate, VendorName, BrandName, ContactPerson            string
	ContactNumber                                                                 any
	ItemName, ItemImage                                                           string
	NetWeight, CartoonPack, StorageTemperature, ShelfLife, ShelfPrice, KottofCost number
	SupplyType, CoveredAreas, MinimumOrderQty, ContractDate, ReturnPolicy, Notes  string
	InActive                                                                      string
}

func main() {
	req, _ := http.NewRequest("GET", "https://script.google.com/macros/s/AKfycbzw0TKWycxeB5sx1wIefAiEHeYQt2mVuM-NAZTccxedhyntdv8FvcUteOZ2k03wRHGE/exec?", nil)

	q := req.URL.Query()
	q.Add("barcode", "6287029390129")
	//q.Add("another_thing", "foo & bar")
	req.URL.RawQuery = q.Encode()

	fmt.Println(req.URL.String())

	// url := "https://script.google.com/macros/s/AKfycbzw0TKWycxeB5sx1wIefAiEHeYQt2mVuM-NAZTccxedhyntdv8FvcUteOZ2k03wRHGE/exec?barcode=6287029390129"
	// resp, err := http.Get(req.URL.String())
	resp, err := http.DefaultClient.Do(req)
	_ = req.URL.RawQuery
	if err != nil {
		log.Fatalln(err)
	}

	//We Read the response body on the line below.
	/* body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatalln(err)
	}
	//Convert the body to type string
	sb := string(body)
	log.Printf(sb) */

	//	var target interface{}
	var target = new(SKUcard[float64])
	err = json.NewDecoder(resp.Body).Decode(target)
	if err != nil {
		fmt.Println("err:", err)
	}

	str := fmt.Sprintf("%v", target.BarCode)
	fmt.Println(str)

    fmt.Println(reflect.TypeOf(target.BarCode))
}

That is the output as:

6.287029390129e+12
float64

My point is, the barcode I’m getting from the server should be a string, but in some cases it is a number.
In my struct above if I defined barcode as string, then I’m getting the below runtime error:

type SKUcard[number Number] struct {
	BarCode, SKUCode                                                              string
...
}

// Error:
err: json: cannot unmarshal number into Go struct field SKUcard[float64].BarCode of type string

If I defined the barcode as any as in my full code above, and the code in the server entered in the field is number, then I’m getting it in the scientific format, that is:

6.287029390129e+12

In the above code, output should be 6287029390129 with a type of string

Have you considered using json.Number?

It’s a bit clunky to work with, but it’s relatively stable to use.

Also, of course if you specify float you get a float. Floats are known to be inexact, and should not be used anywhere where accuracy is a requirement.

Thanks, I tried the below receiver, and it worked with me:

type AnyString string

func (s *AnyString) UnmarshalJSON(data []byte) error {
	fmt.Println(fmt.Sprintf("%s", data))
	const layout = "2006-01-02T03:04:05.999Z"
	if data[0] != '"' { // not string, so probably int, make it a string by wrapping it in double quotes
		data = []byte(`"` + string(data) + `"`)
	} else if len(data) > 4 { // clean date and return date part only without time
		timestamp := fmt.Sprintf("%s", data)
		stamp, err := strconv.Unquote(timestamp) // my date appeared as: "\"2022-04-28T12:32:27.242Z\""
		if err != nil {
			fmt.Println(err)
		}
		t, error := time.Parse(layout, stamp)

		if error != nil {
			fmt.Println(error)
		} else {
			fmt.Println("valid!:", t)
			y, m, d := t.Date()
			fmt.Printf("%v/%v/%v", d, m, y)
			data = []byte(`"` + fmt.Sprintf("%v/%v/%v", d, m, y) + `"`)
		}
	}

	// unmarshal as plain string
	return json.Unmarshal(data, (*string)(s))
}

Any in my struct, I used:

type SKUcard[number Number] struct {
    BarCode, SKUCode, VendorCode, RegistrationDate                                AnyString
...
}