In golang I have two dimensional slice of pointers to struct, as shown in code below.
type point struct {
x int
y int
}
type cell struct {
point point
visited bool
walls walls
}
type walls struct {
n bool
e bool
s bool
w bool
}
type maze struct {
cells [][]*cell
solutionStack Stack
}
I would like to serialize cells slice into JSON. But as all the elements are pointers calling encode will give empty JSON. What would be the best way to serialize this slice.
One solution that comes to my mid is to create a local copy of this 2D slice ad replace all pointers with actual struct. It'll work but it is no
I'm not sure if I'm answering your question because the built in JSON package will do the reflection of the pointers automatically. It should "just work". I did notice that you are not exporting the properties in your struct, maybe that is the issue you have? When using reflection, you cannot inspect unexported values.
http://play.golang.org/p/zTuMLBgGWk
package main
import (
"encoding/json"
"fmt"
)
type point struct {
X int
Y int
}
type cell struct {
Point point
Visited bool
Walls walls
}
type walls struct {
N bool
E bool
S bool
W bool
}
type maze struct {
Cells [][]*cell
}
func main() {
m := maze{}
var row1 []*cell
var row2 []*cell
row1 = append(row1, &cell{
Point: point{1, 2},
Walls: walls{N: true},
})
row2 = append(row2, &cell{
Point: point{3, 4},
Walls: walls{E: true},
})
m.Cells = append(m.Cells, row1, row2)
mazeJson, _ := json.MarshalIndent(m, "", " ")
fmt.Println(string(mazeJson))
}
Related
what I try to do
I try to pass an instance of a struct - including json tags to a func, create a new instance, and set value on field
after this i try to serialize (JSON), but the values are empty
NOTICE: i looked up loads of articles on SO about setting values via reflection, but it seems i missed a little detail
struct definition
this part defines the struct with json and xml tags
type Person struct {
Name string `json:"Name" xml:"Person>FullName"`
Age int `json:"Age" xml:"Person>Age"`
}
create instance (+wrapping into empty interface)
afterwards I create an instance and store it in an interface{} - why? because in my production code this stuff will be done in a func which accepts a interface{}
var iFace interface{} = Person{
Name: "Test",
Age: 666,
}
creating a new instance of the struct and setting values via reflection
iFaceType := reflect.TypeOf(iFace)
item := reflect.New(iFaceType)
s := item.Elem()
if s.Kind() == reflect.Struct {
fName := s.FieldByName("Name")
if fName.IsValid() {
// A Value can be changed only if it is
// addressable and was not obtained by
// the use of unexported struct fields.
if fName.CanSet() {
// change value of N
switch fName.Kind() {
case reflect.String:
fName.SetString("reflectedNameValue")
fmt.Println("Name was set to reflectedNameValue")
}
}
}
fAge := s.FieldByName("Age")
if fAge.IsValid() {
// A Value can be changed only if it is
// addressable and was not obtained by
// the use of unexported struct fields.
if fAge.CanSet() {
// change value of N
switch fAge.Kind() {
case reflect.Int:
x := int64(42)
if !fAge.OverflowInt(x) {
fAge.SetInt(x)
fmt.Println("Age was set to", x)
}
}
}
}
}
Question
what am I doing wrong?
in production code I fill multiple copies with data and add it to a slice...
but this only makes sense if the json tags are kept in place and the stuff serializes just the same way.
code sample for play
package main
import (
"encoding/json"
"fmt"
"reflect"
)
func main() {
type Person struct {
Name string `json:"Name" xml:"Person>FullName"`
Age int `json:"Age" xml:"Person>Age"`
}
var iFace interface{} = Person{
Name: "Test",
Age: 666,
}
fmt.Println("normal: \n" + JSONify(iFace))
iFaceType := reflect.TypeOf(iFace)
item := reflect.New(iFaceType)
s := item.Elem()
if s.Kind() == reflect.Struct {
fName := s.FieldByName("Name")
if fName.IsValid() {
// A Value can be changed only if it is
// addressable and was not obtained by
// the use of unexported struct fields.
if fName.CanSet() {
// change value of N
switch fName.Kind() {
case reflect.String:
fName.SetString("reflectedNameValue")
fmt.Println("Name was set to reflectedNameValue")
}
}
}
fAge := s.FieldByName("Age")
if fAge.IsValid() {
// A Value can be changed only if it is
// addressable and was not obtained by
// the use of unexported struct fields.
if fAge.CanSet() {
// change value of N
switch fAge.Kind() {
case reflect.Int:
x := int64(42)
if !fAge.OverflowInt(x) {
fAge.SetInt(x)
fmt.Println("Age was set to", x)
}
}
}
}
}
fmt.Println("reflected: \n" + JSONify(item))
}
func JSONify(v interface{}) string {
var bytes []byte
bytes, _ = json.MarshalIndent(v, "", "\t")
return string(bytes)
}
Your item is of type reflect.Value. You have to call Value.Interface() to obtain the value wrapped in it:
fmt.Println("reflected: \n" + JSONify(item.Interface()))
With this change, output will be (try it on the Go Playground):
normal:
{
"Name": "Test",
"Age": 666
}
Name was set to reflectedNameValue
Age was set to 42
reflected:
{
"Name": "reflectedNameValue",
"Age": 42
}
reflect.Value itself is also a struct, but obviously trying to marshal it will not be identical to marshaling a Person struct value. reflect.Value does not implement marshaling the wrapped data to JSON.
There are two structures A & B. B includes A. Also there is a function attached to A. It returns json of the parent object. I expect to see all object fields in json when I call the fonction on instance of B, but I get only fields of A. Please look at the code:
type A struct {
Foo string
}
type B struct {
A
Bar string
}
func (object *A) toJson() []byte {
res, _ := json.Marshal(&object)
return res
}
func main() {
b := B{}
fmt.Println(string(b.toJson()))
}
I expect to get {"Foo":"", "Bar":""} but the result is {"Foo":""}. The first way is to define two separate functions for both of structures. But is there the second solution with one function? Thank you in advance.
Your methodn toJson() is from A struct. change it to struct B then you will get your expected result.
package main
import (
"encoding/json"
"fmt"
)
type A struct {
Foo string `json:"foo"`
}
type B struct {
A
Bar string `json:"bar"`
}
func (object *B) toJson() []byte {
res, _ := json.Marshal(&object)
return res
}
func main() {
c := B{}
fmt.Println(string(c.toJson()))
}
Since toJson is defined for A, it operates on b.A. Embedding a type in Go is not the same as subclassing in other languages. See https://golang.org/doc/effective_go.html#embedding.
It it possible in Golang to use more than one name for a JSON struct tag ?
type Animation struct {
Name string `json:"name"`
Repeat int `json:"repeat"`
Speed uint `json:"speed"`
Pattern Pattern `json:"pattern",json:"frames"`
}
you can use multiple json tag with third part json lib like github.com/json-iterator/go
coding like below:
package main
import (
"fmt"
"github.com/json-iterator/go"
)
type TestJson struct {
Name string `json:"name" newtag:"newname"`
Age int `json:"age" newtag:"newage"`
}
func main() {
var json = jsoniter.ConfigCompatibleWithStandardLibrary
data := TestJson{}
data.Name = "zhangsan"
data.Age = 22
byt, _ := json.Marshal(&data)
fmt.Println(string(byt))
var NewJson = jsoniter.Config{
EscapeHTML: true,
SortMapKeys: true,
ValidateJsonRawMessage: true,
TagKey: "newtag",
}.Froze()
byt, _ = NewJson.Marshal(&data)
fmt.Println(string(byt))
}
output:
{"name":"zhangsan","age":22}
{"newname":"zhangsan","newage":22}
See How to define multiple name tags in a struct on how you can define multiple tags on one struct field.
You can also use a type Info map[string]interface{} instead of your struct.
Or you can use both types in your structure, and make method Details() which will return right pattern.
type Animation struct {
Name string `json:"name"`
Repeat int `json:"repeat"`
Speed uint `json:"speed"`
Pattern Pattern `json:"pattern"`
Frame Pattern `json:"frames"`
}
func (a Animation) Details() Pattern {
if a.Pattern == nil {
return a.Frame
}
return a.Pattern
}
I have the following test code:
package main
import (
"fmt"
"testing"
"encoding/json"
)
type Coll1 struct {
A string
B string
C string
}
type Coll2 struct {
A *string
B *string
C *string
}
var as = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
var bs = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
var cs = "ccccccccccccccccccccccccccccccccc"
func testBM1(b *testing.B) {
for i := 0; i<b.N; i++ {
json.Marshal(Coll1{as,bs,cs})
}
}
func testBM2(b *testing.B) {
for i := 0; i<b.N; i++ {
json.Marshal(Coll2{&as,&bs,&cs})
}
}
func main() {
fmt.Println(testing.Benchmark(testBM1))
fmt.Println(testing.Benchmark(testBM2))
}
I would expect the second case to run faster since it is using pointers and therefore doesn't have to copy the strings, but in fact it runs at about 4250 ns/op where the first runs near 2800 ns/op. Can anyone shed any light on why this might be?
Edit: Darshan Computing suggested that this may hold true for embedded structs even. A simple test confirms this:
package main
import (
"fmt"
"testing"
"encoding/json"
)
type Coll1 struct {
A,B,C string
}
type Coll1Outer struct {
A,B,C Coll1
}
type Coll2Outer struct {
A,B,C *Coll2
}
type Coll2 struct {
A,B,C *string
}
var as = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
var bs = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
var cs = "ccccccccccccccccccccccccccccccccc"
func testBM1(b *testing.B) {
for i := 0; i<b.N; i++ {
c := Coll1Outer{ Coll1{as,bs,cs},
Coll1{as,bs,cs},
Coll1{as,bs,cs} }
json.Marshal(c)
}
}
func testBM2(b *testing.B) {
for i := 0; i<b.N; i++ {
c := Coll2Outer{ &Coll2{&as,&bs,&cs},
&Coll2{&as,&bs,&cs},
&Coll2{&as,&bs,&cs} }
json.Marshal(c)
}
}
func main() {
fmt.Println(testing.Benchmark(testBM1))
fmt.Println(testing.Benchmark(testBM2))
}
For me this shows the non-pointer struct taking about 12ms/op, while the one with pointers takes 13ms/op. Not a huge difference, but it's interesting that the property still holds.
I notice the biggest percentage difference in ns/op when I set as, bs, and cs to "a", "b", and "c", respectively. As I increase the length of the strings, they approach each other. They seem to always be about 1000 ns/op different.
So I believe all that's going on is that it takes 1000 ns on my machine (1450 on yours) to reflect and follow the pointers. Passing a smaller struct up front doesn't seem to counteract this effect because once the pointers are followed, Marshal still passes the data around internally in the process of generating and returning the equivalent JSON.
Simple version
How can you create a variable of a certain type based upon the value of a string?
type ta struct { a int }
type tb struct { b float }
type tc struct { c string }
t := "tb"
v := MagicVarFunc(t) // Returns a new allocated var of type interface{}
v.(tb).b = 8.3
The true example
In my, surprisingly enough, working example below, I am dynamically creating variables based on a string. This is done by registering each struct type in a map with the string being the key and a nil-pointer of the type being the value.
Each type implements an interface with the method New() which returns a new variable of that specific type.
The example below is very close to what I wish to do, where each action has a set of JSON encoded data which will populate the corresponding struct. The way I've structured it is also because I wish to be able to create new stand alone actions that I register to the map.
I am not sure if am abusing the language now.
May anyone give me any pointers if I am completely out of my mind? Is there an obviously easier way?
package main
import (
"fmt"
"encoding/json"
)
// All I require of an action is that it may be executed
type ActionHandler interface {
Exec()
New() ActionHandler
}
// My list of actions
var mActions = make(map[string]ActionHandler)
// Action Exit (leaving the program)
type aExit struct {}
func (s *aExit) Exec() { fmt.Println("Good bye") }
func (s *aExit) New() ActionHandler { return new(aExit) }
func init() {
var a *aExit
mActions[`exit`] = a
}
// Action Say (say a message to someone)
type aSay struct {
To string
Msg string
}
func (s *aSay) Exec() { fmt.Println(`You say, "` + s.Msg + `" to ` + s.To) }
func (s *aSay) New() ActionHandler { return new(aSay) }
func init() {
var a *aSay
mActions[`say`] = a
}
func inHandler(action string, data []byte) {
a := mActions[action].New()
json.Unmarshal(data, &a)
a.Exec()
}
func main(){
inHandler(`say`, []byte(`{"to":"Sonia","msg":"Please help me!"}`))
inHandler(`exit`, []byte(`{}`))
}
You can use reflection to get the zero value of, or to allocate a new value (like new) of a type using reflection, if you can get the Type value at runtime. However, I don't think there is a way to get the Type from a string. You would need to have a value of that type to get the type itself.
I adopted your idea, of using a map. I map the string to the type itself, which you can get using reflect.TypeOf, which gets the type out of an interface value. Then I used reflect.Zero to get the zero value of that type (a convenient value that exists for every type). Then I got the value out as an interface.
package main
import "reflect"
type ta struct { a int }
type tb struct { b float64 }
type tc struct { c string }
var mActions map[string]reflect.Type = make(map[string]reflect.Type)
func init() {
var a ta
mActions[`ta`] = reflect.TypeOf(a)
var b tb
mActions[`tb`] = reflect.TypeOf(b)
var c ta
mActions[`tc`] = reflect.TypeOf(c)
}
func MagicVarFunc(action string) interface{} {
return reflect.Zero(mActions[action]).Interface()
}
func main() {
t := "tb"
v := MagicVarFunc(t) // Returns a new allocated var of type interface{}
x := v.(tb)
x.b = 8.3
}
jorelli's answer is very good. I'm just going to show a few options. Your "true example" looks essentially like command dispatch, with command parameters specified with JSON. To start with simple code that does this,
package main
import (
"encoding/json"
"fmt"
)
func inHandler(action string, data []byte) {
arg := make(map[string]interface{})
json.Unmarshal(data, &arg)
switch action {
case "say":
fmt.Printf("You say, %q to %s\n", arg["msg"], arg["to"])
case "exit":
fmt.Println("Good bye")
}
}
func main() {
inHandler(`say`, []byte(`{"to":"Sonia","msg":"Please help me!"}`))
inHandler(`exit`, []byte(`{}`))
}
Your register new commands by adding cases to the switch statement. Yeah, didn't think you'd like that. So, adding your map and init() idea,
package main
import (
"encoding/json"
"fmt"
)
type jmap map[string]interface{}
var mActions = map[string]func(jmap){}
func init() {
mActions["say"] = func(arg jmap) {
fmt.Printf("You say, %q to %s\n", arg["msg"], arg["to"])
}
}
func init() {
mActions["exit"] = func(jmap) { fmt.Println("Good bye") }
}
func inHandler(action string, data []byte) {
args := make(jmap)
json.Unmarshal(data, &args)
mActions[action](args)
}
func main() {
inHandler(`say`, []byte(`{"to":"Sonia","msg":"Please help me!"}`))
inHandler(`exit`, []byte(`{}`))
}
Now if you wanted, you could put each of those init functions in a separate source file and new commands could be registered by creating a new source file with a new init function.
The rest of the program is simplified with some assumptions that the commands have flat argument lists that the JSON will always encode as an object. This allows you to dispense with separate Go struct definitions for each command. inHandler just creates the same type of object (a map) for all commands, unmarshals into it, and passes it to the command. If you wanted to handle a little more arbitrary JSON, you could unmarshal into an empty interface, and the functions would have to do some extra work to dig out the arguments. If that was too much work and you really wanted to unmarshal directly into a struct, then you arrive near jorelli's solution of making each command function unmarshal its own JSON.
start by defining a function type that does the thing you want:
type Producer func([]byte) interface{}
make a few of them:
func FooProducer(raw []byte) interface{} {
foo := new(Foo)
... // do something to foo
return foo
}
func BarProducter(raw []byte) interface{} {
bar := new(Bar)
... // do something to bar
return bar
}
stick them in a map:
likeThis := map[string]Producer{
"foo": FooProducer,
"bar": BarProducer,
}
and then just do one of these:
myVal := likeThis[someString](raw)
but you probably want to define some interface and make your producer something more like:
type Producer func([]byte) MyAwesomeInterface
since there's probably some common stuff you want to do with those things you're decoding. You also probably want to handle the case of a bad string input, like-a-this:
f, ok := likeThis[someString]
if !ok {
// return, break, panic... something, just get the hell away from here.
}
myVal := f(raw)
The whole notion of inspecting types is kinda cumbersome in Go. It's generally less work to just add new types than it is to try to do reflection gymnastics with the type system.