struct not been entirely marshaled - struct

I have a struct what I need to marshal to consume the webservice, but in my tests I the Marshal function only encode one field:
type DataRows []struct {
mData interface{}
}
type DataColumns []struct {
mColumnName string
mColumnType int
mColumnPrecision int
mColumnScale int
}
type DataTables []struct {
mDataColumns DataColumns
mDataRows DataRows
mIndex int
}
type CFFDataSet struct {
mDataTables DataTables
mUser string
DBServer int
}
func main() {
ds := CFFDataSet{
mDataTables: DataTables{{
mDataColumns: DataColumns{{
mColumnName: "Test",
mColumnType: 1,
mColumnPrecision: 1,
mColumnScale: 1,
}},
mDataRows: DataRows{{
mData: "Test",
}},
mIndex: 0,
}},
mUser: "Teste",
DBServer: 2,
}
marchaled, _ := json.Marshal(ds)
fmt.Println(string(marchaled))
}
is returning
$ go run getrest.go
{"DBServer":2}
Can someone give me a hint why not this working ?

All your other fields are unexported (like private in other languages) and the unmarshaller can't access them. This is designated by the case of the first letter in the field name, needs to be uppercase.
For reference, here's an example using a field name on your struct that differs from the json's field name;
var jsonBlob = []byte(`[
{"Name": "Platypus", "Purchase": "Monotremata"},
{"Name": "Quoll", "Purchase": "Dasyuromorphia"}
]`)
type Animal struct {
Name string
Order string `json:"Purchase"`
}
var animals []Animal
err := json.Unmarshal(jsonBlob, &animals)
if err != nil {
fmt.Println("error:", err)
}
fmt.Printf("%+v", animals)
https://play.golang.org/p/iJqaXQY7Ch

Related

How to custome text of specific filed of a struct when call fmt.Printf("%+v", obj)

For example, there is a struct Student
type Student struct {
Filed1 string
Filed2 string
Filed3 string
Name *string
Data []byte
}
func main(){
name := "john"
s := Student3{
Filed1: "a",
Filed2: "b",
Filed3: "c",
Name: &name,
Data: []byte{1, 2, 3},
}
fmt.Printf("%+v", s)
}
The print result is:{Filed1:a Filed2:b Filed3:c Name:0xc000167230 Data:[1 2 3]}%
But I want custome the String() output of fields Name and Data
output of Name field be the origin value, not the pointer
output of Date field be the hex string, "0x010203", which is result of hex.EncodeToString(xxx)
So it's output will be {Filed1:a Filed2:b Filed3:c Name:"john" Date:"0x010203"}
Is there a simple way to implement it?
You have a couple of options. Like Volker wrote in his comment you can implement the String method on the struct. You can also use json.Marshal/MarshalIndent if you want it json formatted. That also gives you the option to name the fields differently in your output.
Here's an example of it:
package main
import (
"encoding/json"
"fmt"
)
type Student struct {
Field1 string `json:"fieldNameInJSON"`
Field2 string
Field3 string
Name *string
Data []byte
}
func (s Student) String() string {
return fmt.Sprintf("{ Field1: %s, Field2: %s, Field3: %s, Name: %s, Data: %v}", s.Field1, s.Field2, s.Field3, *s.Name, s.Data)
}
func main() {
name := "john"
s := Student{
Field1: "a",
Field2: "b",
Field3: "c",
Name: &name,
Data: []byte{1, 2, 3},
}
fmt.Printf("%+v\n", s)
fmt.Println(s)
j, e := json.Marshal(s)
if e == nil {
fmt.Println(string(j))
}
j, e = json.MarshalIndent(s, " ", " ")
if e == nil {
fmt.Println(string(j))
}
}
If you run in on play you get the output:
{ Field1: a, Field2: b, Field3: c, Name: john, Data: [1 2 3]}
{ Field1: a, Field2: b, Field3: c, Name: john, Data: [1 2 3]}
{"fieldNameInJSON":"a","Field2":"b","Field3":"c","Name":"john","Data":"AQID"}
{
"fieldNameInJSON": "a",
"Field2": "b",
"Field3": "c",
"Name": "john",
"Data": "AQID"
}
*Edit:
I missed you wanted to run hex.EncodeToString on the data field, you can of course add that in the String() method. If you want to do it for json you'll have to implement a Marshaler like described in this answer

Using reflection SetString

I have a struct like this one:
type ProductionInfo struct {
StructA []Entry
}
type Entry struct {
Field1 string
Field2 int
}
I would like to change the value of Field1 using reflection but the reflect object returned always CanSet() = false. What can I do? See playground example.
https://play.golang.org/p/eM_KHC3kQ5
Here is the code:
func SetField(source interface{}, fieldName string, fieldValue string) {
v := reflect.ValueOf(source)
tt := reflect.TypeOf(source)
for k := 0; k < tt.NumField(); k++ {
fieldValue := reflect.ValueOf(v.Field(k))
fmt.Println(fieldValue.CanSet())
if fieldValue.CanSet() {
fieldValue.SetString(fieldValue.String())
}
}
}
func main() {
source := ProductionInfo{}
source.StructA = append(source.StructA, Entry{Field1: "A", Field2: 2})
SetField(source, "Field1", "NEW_VALUE")
}
Multiple errors. Let's iterate over them.
First, you pass a value of ProductionInfo and not a value of Entry whose field you want to modify, so first change it to:
SetField(source.StructA[0], "Field1", "NEW_VALUE")
Next, you are passing a (non-pointer) value. You can't modify the fields of a non-pointer struct with reflection, because that would only modify a copy which would be discarded. In order to avoid this (and further confusion), this is not allowed (CanSet() returns false). So you have to pass a pointer to the struct:
SetField(&source.StructA[0], "Field1", "NEW_VALUE")
Now inside SetField() the reflect.ValueOf(source) will describe the passed pointer. You may use Value.Elem() to navigate to the reflect.Value of the pointed object (the struct value):
v := reflect.ValueOf(source).Elem()
And now it works. Modified code:
func SetField(source interface{}, fieldName string, fieldValue string) {
v := reflect.ValueOf(source).Elem()
fmt.Println(v.FieldByName(fieldName).CanSet())
if v.FieldByName(fieldName).CanSet() {
v.FieldByName(fieldName).SetString(fieldValue)
}
}
func main() {
source := ProductionInfo{}
source.StructA = append(source.StructA, Entry{Field1: "A", Field2: 2})
fmt.Println("Before: ", source.StructA[0])
SetField(&source.StructA[0], "Field1", "NEW_VALUE")
fmt.Println("After: ", source.StructA[0])
}
Output (try it on the Go Playground):
Before: {A 2}
true
After: {NEW_VALUE 2}

Golang - Unmarshal/rebuild an object in 2 step passing by interface

I'm working with json and golang. I've made a TCP server and, I need to Unmarshal the message to know which type of service is asked, before Unmarshal the contained data. It's a bit hard to explain so this is my code:
package main
import (
"fmt"
"encoding/json"
)
type Container struct {
Type string
Object interface{}
}
type Selling struct {
Surname string
Firstname string
//......
Price int
}
type Buying struct {
ID int
Surname string
Firstname string
//..........
}
/*
type Editing struct {
ID int
...............
}
Informations, etc etc
*/
func main() {
tmp_message_json1 := Selling{Surname: "X", Firstname: "Mister", Price: 10}
//tmp_message_json1 := Buying{ID: 1, Surname: "X", Firstname: "Mister"}
tmp_container_json1 := Container{Type: "Selling", Object: tmp_message_json1}
json_tmp, _ := json.Marshal(tmp_container_json1)
/*...........
We init tcp etc etc and then a message comes up !
...........*/
c := Container{}
json.Unmarshal(json_tmp, &c)
//I unmarshal a first time to know the type of service asked
// first question: Does Unmarshal need to be used only one time?
// does I need to pass c.Object as a string to unmarshal it in the called functions?
if c.Type == "Buying" {
takeInterfaceBuying(c.Object)
} else if c.Type == "client" {
takeInterfaceSelling(c.Object)
} else {
fmt.Println("bad entry")
}
}
func takeInterfaceBuying(Object interface{}) {
bu := Object
fmt.Println(bu.Firstname, bu.Surname, "wants to buy the following product:", bu.ID)
}
func takeInterfaceSelling(Object interface{}) {
se := Object
fmt.Println(se.Firstname, se.Surname, "wants to sell something for:", se.Price)
}
I need to handle messages which comes up like it, but I don't know if it's possible? does it possible?
Thank for help !
There is json.RawMessage for this purpose.
package main
import (
"encoding/json"
"fmt"
)
type Container struct {
Type string
Object json.RawMessage
}
type Selling struct {
Surname string
Firstname string
Price int
}
type Buying struct {
ID int
Surname string
Firstname string
}
func main() {
rawJson1 := []byte(`{"Type":"Selling","Object":{"Surname":"X","Firstname":"Mister","Price":10}}`)
rawJson2 := []byte(`{"Type":"Buying","Object":{"ID":1,"Surname":"X","Firstname":"Mister"}}`)
processMessage(rawJson1)
processMessage(rawJson2)
}
func processMessage(data []byte) {
var c Container
json.Unmarshal(data, &c)
switch {
case c.Type == "Buying":
processBuying(c)
case c.Type == "Selling":
processSelling(c)
default:
fmt.Println("bad entry")
}
}
func processBuying(c Container) {
var bu Buying
json.Unmarshal(c.Object, &bu)
fmt.Println(bu.Firstname, bu.Surname, "wants to buy the following product:", bu.ID)
}
func processSelling(c Container) {
var se Selling
json.Unmarshal(c.Object, &se)
fmt.Println(se.Firstname, se.Surname, "wants to sell something for:", se.Price)
}
I might be wrong, but I don't think you can do it in one step.
First idea: Unmarshal in map[string]interface{}
Don't use type with unmarshal, instead use a map[string]interface{}, and then construct Selling/Buying from this map (or use directly the map)
type Container struct {
Type string
Object map[string]interface{}
}
Second idea: Two steps / clueless container
First: Unmarshall in a clueless Container that doesn't know the type
type CluelessContainer struct {
Type string
Object interface{} `json:"-"` // or just remove this line ?
}
Then unmarshall in the type aware container. You could use a factory pattern to come with the right struct.

How to print struct variables in console?

How can I print (to the console) the Id, Title, Name, etc. of this struct in Golang?
type Project struct {
Id int64 `json:"project_id"`
Title string `json:"title"`
Name string `json:"name"`
Data Data `json:"data"`
Commits Commits `json:"commits"`
}
To print the name of the fields in a struct:
fmt.Printf("%+v\n", yourProject)
From the fmt package:
when printing structs, the plus flag (%+v) adds field names
That supposes you have an instance of Project (in 'yourProject')
The article JSON and Go will give more details on how to retrieve the values from a JSON struct.
This Go by example page provides another technique:
type Response2 struct {
Page int `json:"page"`
Fruits []string `json:"fruits"`
}
res2D := &Response2{
Page: 1,
Fruits: []string{"apple", "peach", "pear"}}
res2B, _ := json.Marshal(res2D)
fmt.Println(string(res2B))
That would print:
{"page":1,"fruits":["apple","peach","pear"]}
If you don't have any instance, then you need to use reflection to display the name of the field of a given struct, as in this example.
type T struct {
A int
B string
}
t := T{23, "skidoo"}
s := reflect.ValueOf(&t).Elem()
typeOfT := s.Type()
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
fmt.Printf("%d: %s %s = %v\n", i,
typeOfT.Field(i).Name, f.Type(), f.Interface())
}
I want to recommend go-spew, which according to their github "Implements a deep pretty printer for Go data structures to aid in debugging"
go get -u github.com/davecgh/go-spew/spew
usage example:
package main
import (
"github.com/davecgh/go-spew/spew"
)
type Project struct {
Id int64 `json:"project_id"`
Title string `json:"title"`
Name string `json:"name"`
Data string `json:"data"`
Commits string `json:"commits"`
}
func main() {
o := Project{Name: "hello", Title: "world"}
spew.Dump(o)
}
output:
(main.Project) {
Id: (int64) 0,
Title: (string) (len=5) "world",
Name: (string) (len=5) "hello",
Data: (string) "",
Commits: (string) ""
}
my 2cents would be to use json.MarshalIndent -- surprised this isn't suggested, as it is the most straightforward. for example:
func prettyPrint(i interface{}) string {
s, _ := json.MarshalIndent(i, "", "\t")
return string(s)
}
no external deps and results in nicely formatted output.
I think it would be better to implement a custom stringer if you want some kind of formatted output of a struct
for example
package main
import "fmt"
type Project struct {
Id int64 `json:"project_id"`
Title string `json:"title"`
Name string `json:"name"`
}
func (p Project) String() string {
return fmt.Sprintf("{Id:%d, Title:%s, Name:%s}", p.Id, p.Title, p.Name)
}
func main() {
o := Project{Id: 4, Name: "hello", Title: "world"}
fmt.Printf("%+v\n", o)
}
p = Project{...}
fmt.Printf("%+v", p)
fmt.Printf("%#v", p) //with type
Alternatively, try using this function PrettyPrint()
// print the contents of the obj
func PrettyPrint(data interface{}) {
var p []byte
// var err := error
p, err := json.MarshalIndent(data, "", "\t")
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%s \n", p)
}
In order to use this you do not need any additional packages with the exception of fmt and encoding/json, just a reference, pointer to, or literal of the struct you have created.
To use just take your struct, initialize it in main or whatever package you are in and pass it into PrettyPrint().
type Prefix struct {
Network string
Mask int
}
func valueStruct() {
// struct as a value
var nw Prefix
nw.Network = "10.1.1.0"
nw.Mask = 24
fmt.Println("### struct as a pointer ###")
PrettyPrint(&nw)
}
It's output would be
### struct as a pointer ###
{
"Network": "10.1.1.0",
"Mask": 24
}
Play around with the code here.
It is very convenient to use package fmt to output:
fmt.Printf("%+v \n", yourProject)
if you want to see the full type of the sturct, you can use # replace + :
fmt.Printf("%#v \n", yourProject)
I recommend to use Pretty Printer Library. In that you can print any struct very easily.
Install Library
https://github.com/kr/pretty
or
go get github.com/kr/pretty
Now do like this in your code
package main
import (
fmt
github.com/kr/pretty
)
func main(){
type Project struct {
Id int64 `json:"project_id"`
Title string `json:"title"`
Name string `json:"name"`
Data Data `json:"data"`
Commits Commits `json:"commits"`
}
fmt.Printf("%# v", pretty.Formatter(Project)) //It will print all struct details
fmt.Printf("%# v", pretty.Formatter(Project.Id)) //It will print component one by one.
}
Also you can get difference between component through this library and so more. You can also have a look on library Docs here.
I like litter.
From their readme:
type Person struct {
Name string
Age int
Parent *Person
}
litter.Dump(Person{
Name: "Bob",
Age: 20,
Parent: &Person{
Name: "Jane",
Age: 50,
},
})
Sdump is pretty handy in tests:
func TestSearch(t *testing.T) {
result := DoSearch()
actual := litterOpts.Sdump(result)
expected, err := ioutil.ReadFile("testdata.txt")
if err != nil {
// First run, write test data since it doesn't exist
if !os.IsNotExist(err) {
t.Error(err)
}
ioutil.Write("testdata.txt", actual, 0644)
actual = expected
}
if expected != actual {
t.Errorf("Expected %s, got %s", expected, actual)
}
}
To print the struct as JSON:
fmt.Printf("%#v\n", yourProject)
Also possible with (as it was mentioned above):
fmt.Printf("%+v\n", yourProject)
But the second option prints string values without "" so it is harder to read.
I suggest u use fmt.Printf("%#v\n", s) , It will print golang type at the same time
package main
import (
"fmt"
"testing"
)
type student struct {
id int32
name string
}
type Project struct {
Id int64 `json:"project_id"`
Title string `json:"title"`
Name string `json:"name"`
}
func TestPrint(t *testing.T) {
s := Project{1, "title","jack"}
fmt.Printf("%+v\n", s)
fmt.Printf("%#v\n", s)
}
result:
{Id:1 Title:title Name:jack}
main.Project{Id:1, Title:"title", Name:"jack"}
You can do the json mashal first and print it as a string. There you can see it the whole struct value completely.
package main
import "fmt"
import "json"
type Project struct {
Id int64 `json:"project_id"`
Title string `json:"title"`
Name string `json:"name"`
}
func main() {
o := Project{Id: 4, Name: "hello", Title: "world"}
om, _ := json.marshal(o)
log.Printf("%s\n", string(om))
}
When you have more complex structures, you might need to convert to JSON before printing:
// Convert structs to JSON.
data, err := json.Marshal(myComplexStruct)
fmt.Printf("%s\n", data)
Source: https://gist.github.com/tetsuok/4942960
Sometimes, it might be handy to print the struct as valid Go code (the go/ast equivalent). For this purpose, https://github.com/hexops/valast does a great job:
package main
import (
"fmt"
"github.com/hexops/valast"
)
type ProjectData struct {
Title string `json:"title"`
Name string `json:"name"`
Data string `json:"data"`
Commits string `json:"commits"`
}
type Project struct {
Id int64 `json:"project_id"`
Data *ProjectData `json:"data"`
}
func main() {
p := Project{
Id: 1,
Data: &ProjectData{
Title: "Test",
Name: "Mihai",
Data: "Some data",
Commits: "Test Message",
},
}
fmt.Println(valast.String(p))
}
Output:
go run main.go
Project{Id: 1, Data: &ProjectData{
Title: "Test",
Name: "Mihai",
Data: "Some data",
Commits: "Test Message",
}}
Visit here to see the complete code. Here you will also find a link for an online terminal where the complete code can be run and the program represents how to extract structure's information(field's name their type & value). Below is the program snippet that only prints the field names.
package main
import "fmt"
import "reflect"
func main() {
type Book struct {
Id int
Name string
Title string
}
book := Book{1, "Let us C", "Enjoy programming with practice"}
e := reflect.ValueOf(&book).Elem()
for i := 0; i < e.NumField(); i++ {
fieldName := e.Type().Field(i).Name
fmt.Printf("%v\n", fieldName)
}
}
/*
Id
Name
Title
*/
Maybe this shouldn't be applied for production requests but if you are on debugging mode I suggest you follow the below approach.
marshalledText, _ := json.MarshalIndent(inputStruct, "", " ")
fmt.Println(string(marshalledText))
This results in formatting the data in json format with increased readability.
i suggest to use json.Unmarshal()
i try to print the id with this hope its helpfull:
var jsonString = `{"Id": 1, "Title": "the title", "Name": "the name","Data": "the data","Commits" : "the commits"}`
var jsonData = []byte(jsonString)
var data Project
var err = json.Unmarshal(jsonData, &data)
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println("Id :", data.Id)
There's also go-render, which handles pointer recursion and lots of key sorting for string and int maps.
Installation:
go get github.com/luci/go-render/render
Example:
type customType int
type testStruct struct {
S string
V *map[string]int
I interface{}
}
a := testStruct{
S: "hello",
V: &map[string]int{"foo": 0, "bar": 1},
I: customType(42),
}
fmt.Println("Render test:")
fmt.Printf("fmt.Printf: %#v\n", a)))
fmt.Printf("render.Render: %s\n", Render(a))
Which prints:
fmt.Printf: render.testStruct{S:"hello", V:(*map[string]int)(0x600dd065), I:42}
render.Render: render.testStruct{S:"hello", V:(*map[string]int){"bar":1, "foo":0}, I:render.customType(42)}
fmt.Printf("%+v\n", project)
This is the basic way of printing the details
You don't even need the verb. This dumps everything inside of data:
fmt.Println(data)
very simple
I don't have the structure of Data and Commits So I changed the
package main
import (
"fmt"
)
type Project struct {
Id int64 `json:"project_id"`
Title string `json:"title"`
Name string `json:"name"`
Data string `json:"data"`
Commits string `json:"commits"`
}
func main() {
p := Project{
1,
"First",
"Ankit",
"your data",
"Commit message",
}
fmt.Println(p)
}
For learning you can take help from here : https://gobyexample.com/structs
If you want to write in a log file, as I was searching previously. Then you should use:
log.Infof("Information %+v", structure)
Note:: This will not work with log.Info or log.Debug. In this case, "%v" will get printed, and all the values of the structure will be printed without printing the key/variable name.
A lot of answers for a simple question. I might as well throw my hat in the ring.
package main
import "fmt"
type Project struct {
Id int64 `json:"project_id"`
Title string `json:"title"`
Name string `json:"name"`
//Data Data `json:"data"`
//Commits Commits `json:"commits"`
}
var (
Testy Project
)
func dump_project(foo Project) {
fmt.Println("== Dump Project Struct ====")
fmt.Printf("Id: %d\n", foo.Id)
fmt.Println("Title: ", foo.Title)
fmt.Printf("Name: %v\n", foo.Name)
}
func main() {
fmt.Println("hello from go")
Testy.Id = 3
Testy.Title = "yo"
Testy.Name = "my name"
fmt.Println(Testy)
dump_project(Testy)
}
The output of the various print methods
hello from go
{3 yo my name}
== Dump Project Struct ====
Id: 3
Title: yo
Name: my name
Without using external libraries and with new line after each field:
log.Println(
strings.Replace(
fmt.Sprintf("%#v", post), ", ", "\n", -1))
type Response struct {
UserId int `json:"userId"`
Id int `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
}
func PostsGet() gin.HandlerFunc {
return func(c *gin.Context) {
xs, err := http.Get("https://jsonplaceholder.typicode.com/posts")
if err != nil {
log.Println("The HTTP request failed with error: ", err)
}
data, _ := ioutil.ReadAll(xs`enter code here`.Body)
// this will print the struct in console
fmt.Println(string(data))
// this is to send as response for the API
bytes := []byte(string(data))
var res []Response
json.Unmarshal(bytes, &res)
c.JSON(http.StatusOK, res)
}
}
Another way is, create a func called toString that takes struct, format the
fields as you wish.
import (
"fmt"
)
type T struct {
x, y string
}
func (r T) toString() string {
return "Formate as u need :" + r.x + r.y
}
func main() {
r1 := T{"csa", "ac"}
fmt.Println("toStringed : ", r1.toString())
}
Most of these packages are relying on the reflect package to make such things possible.
fmt.Sprintf() is using -> func (p *pp) printArg(arg interface{}, verb rune) of standard lib
Go to line 638 -> https://golang.org/src/fmt/print.go
Reflection:
https://golang.org/pkg/reflect/
Example code:
https://github.com/donutloop/toolkit/blob/master/debugutil/prettysprint.go
fmt.Println("%+v", structure variable)
A better way to do this would be to create a global constant for the string "%+v" in a package called "commons"(maybe) and use it everywhere in your code
//In commons package
const STRUCTURE_DATA_FMT = "%+v"
//In your code everywhere
fmt.Println(commons.STRUCTURE_DATA_FMT, structure variable)

Golang : Is conversion between different struct types possible?

Let's say I have two similar types set this way :
type type1 []struct {
Field1 string
Field2 int
}
type type2 []struct {
Field1 string
Field2 int
}
Is there a direct way to write values from a type1 to a type2, knowing that they have the same fields ?
(other than writing a loop that will copy all the fields from the source to the target)
Thanks.
To give a reference to OneOfOne's answer, see the Conversions section of the spec.
It states that
A non-constant value x can be converted to type T in any of these
cases:
x is assignable to T.
x's type and T have identical underlying types.
x's type and T are unnamed pointer types and their pointer base types have identical underlying types.
x's type and T are both integer or floating point types.
x's type and T are both complex types.
x is an integer or a slice of bytes or runes and T is a string type.
x is a string and T is a slice of bytes or runes.
The first and highlighted case is your case. Both types have the underlying type
[]struct { Field1 string Field2 int }
An underlying type is defined as
If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself. Otherwise, T's underlying type is the underlying type of the type to which T refers in its type declaration. (spec, Types)
You are using a type literal to define your type so this type literal is your underlying type.
For your specific example, you can easily convert it playground:
t1 := type1{{"A", 1}, {"B", 2}}
t2 := type2(t1)
fmt.Println(t2)
As of Go 1.8, struct tags are ignored when converting a value from one struct type to another. Types type1 and type2 will be convertible, regardless of their struct tags, in that Go release. https://beta.golang.org/doc/go1.8#language
Nicolas, in your later comment you said you were using field tags on the struct; these count as part of definition, so t1 and t2 as defined below are different and you cannot cast t2(t1):
type t1 struct {
Field1 string
}
type t2 struct {
Field1 string `json:"field_1"`
}
UPDATE: This is no longer true as of Go 1.8
This is not the standard way, but if you wish to have a flexible approach to convert a struct to, lets say, a map, or if you want to get rid of some properties of your struct without using `json:"-", you can use JSON marshal.
Concretely, here is what I do:
type originalStruct []struct {
Field1 string
Field2 int
}
targetStruct := make(map[string]interface{}) // `targetStruct` can be anything of your choice
temporaryVariable, _ := json.Marshal(originalStruct)
err = json.Unmarshal(temporaryVariable, &targetStruct)
if err != nil {
// Catch the exception to handle it as per your need
}
Might seem like a hack, but was pretty useful in most of my tasks.
for go v1.18 that already support generic, basically i just create method that accept any type of parameter and convert it to another type with json.Marshal / Unmarshal
// utils.TypeConverter
func TypeConverter[R any](data any) (*R, error) {
var result R
b, err := json.Marshal(&data)
if err != nil {
return nil, err
}
err = json.Unmarshal(b, &result)
if err != nil {
return nil, err
}
return &result, err
}
suppose that i have a struct called models.CreateUserRequest and i want to convert it to models.User. Note that json tag must be same
// models.CreateUserRequest
type CreateUserRequest struct {
Fullname string `json:"name,omitempty"`
RegisterEmail string `json:"email,omitempty"`
}
// models.User
type User struct {
Name string `json:"name,omitempty"`
Email string `json:"email,omitempty"`
Phone string `json:"phone,omitempty"`
}
I can use that utils method above like this
user := models.CreateUserRequest {
Name: "John Doe",
Email: "johndoe#gmail.com"
}
data, err := utils.TypeConverter[models.User](&user)
if err != nil {
log.Println(err.Error())
}
log.Println(reflrect.TypeOf(data)) // will output *models.User
log.Println(data)
You can manually use a mapper function which maps each element of type t1 to type t2. It will work.
func GetT2FromT1(ob1 *t1) *t2 {
ob2 := &t2 { Field1: t1.Field1, }
return ob2
}
Agniswar Bakshi's answer is faster and better if you can write those conversions manually, but here's an expansion on Furqan Rahamath's answer. (A more complete example is available on the Golang playground )
func Recast(a, b interface{}) error {
js, err := json.Marshal(a)
if err != nil {
return err
}
return json.Unmarshal(js, b)
}
// Usage:
type User struct {
Name string
PasswordHash string
}
// remove PasswordHash before providing user:
type PrivateOutgoingUser struct {
Name string
}
u1 := &User{Name: "Alice", PasswordHash: "argon2...."}
u2 := &PrivateOutgoingUser{}
err = Recast(u1, u2)
if err != nil {
log.Panic("Error recasting u1 to u2", err)
}
log.Println("Limited user:", u2)
Here's another way that uses JSON tagging which is faster, since it doesn't require that extra marshal-unmarshal step, but not quite as flexible:
type User struct {
Name string
PasswordHash string `json:"-"` // - removes the field with JSON
}
user := &User{Name: "Tommy Tester", PasswordHash: "argon2...."}
js, err := json.Marshal(user)
log.Println("Limited user:", string(user))

Resources