I have 3 struct: Queue,Config,Tasker
type Queue struct {
Name string
Concurrent int
Connections []*redis.Client
}
type Config struct {
Queues []Queue
RedisAddr string
RedisDB int
}
type Tasker struct {
Config Config
}
The problem happend in this method, I initialize queue.Connections in for-loop, but I got zero length of queue.Connections outside the for-loop
func (t *Tasker) StartListening() {
for j := 0; j < len(t.Config.Queues); j++ {
queue := t.Config.Queues[j]
queue.Connections = make([]*redis.Client, queue.Concurrent)
fmt.Println(len(queue.Connections)) //here print correct length, 1 for default queue, 2 for mail queue
}
fmt.Println(len(t.Config.Queues[0].Connections)) //but why here print 0?
}
This is my test code
func main() {
config := Config{
RedisAddr: "10.1.1.59:6379",
RedisDB: 8,
Queues: []Queue{
Queue{Name: "default", Concurrent: 1},
Queue{Name: "mail", Concurrent: 2},
},
}
daemon := Tasker{Config: config}
daemon.StartListening()
}
why fmt.Println(len(t.Config.Queues[0].Connections)) is 0 outside the for-loop?
You are creating a new Queue instead of accessing the one in the Config structure, and this new value prevents modification to the Queue in Config.Queues. Try direct assignment:
// ...
t.Config.Queues[j].Connections = make([]*redis.Client, queue.Concurrent)
// ...
Or if you want to use an auxillary variable, change Config.Queues type to []*Queue:
type Config struct {
Queues []*Queue
RedisAddr string
RedisDB int
}
// ...
config := Config{
RedisAddr: "10.1.1.59:6379",
RedisDB: 8,
Queues: []*Queue{
&Queue{Name: "default", Concurrent: 1},
&Queue{Name: "mail", Concurrent: 2},
},
}
Now your original code should work.
Related
I need help for transforming this input map into the output map. I try with switch/case and for but I didn't succeed it. Thanks a lot !
Input :
Values{
"toto_voiture_brand": Ad{
"CITROEN": "CITROEN",
},
"toto_voiture_model": Ad{
"CITROEN_toto": "C3",
},
"toto_moto_brand": Ad{
"KAWASAKI": "KAWASAKI",
},
"toto_moto_model": Ad{
"KAWASAKI_tata": "Ninja 1000 SX",
},
"toto_camion_brand": Ad{
"RENAULT": "RENAULT",
"PEUGEOT": "PEUGEOT",
},
"toto_camion_model": Ad{
"RENAULT_toto": "J5",
"PEUGEOT_tata": "255",
},
},
}
Output
Values{
"toto_voiture_model": {
"Citroen": {
{Value: "C3"},
},
},
"toto_moto_model": {
"Kawasaki": {
{Value: "Ninja 1000 SX"},
},
},
"toto_camion_model": {
"RENAULT": {
{Value: "J5"},
},
"PEUGEOT": {
{Value: "255"},
},
},
}
I've tried with switch case and loop for and map. But I don't have the result attendee, I didn't found how to match every map, key and value. Thanks a lot
I should have managed what you need with the following code:
package main
import (
"encoding/json"
"fmt"
"strings"
)
type Output struct {
Value string `json:"Value"`
}
func main() {
// declare output
output := make(map[string]map[string]Output, 0)
// input
input := make(map[string]map[string]string, 0)
input["toto_voiture_brand"] = map[string]string{
"CITROEN": "CITROEN",
}
input["toto_voiture_model"] = map[string]string{
"CITROEN_toto": "C3",
}
input["toto_moto_model"] = map[string]string{
"KAWASAKI_tata": "Ninja 1000 SX",
}
input["toto_camion_model"] = map[string]string{
"RENAULT_toto": "J5",
"PEUGEOT_tata": "255",
}
// transformation
for k, v := range input {
if strings.HasSuffix(k, "_model") {
tempMap := make(map[string]Output, len(v))
for kk, vv := range v {
key := strings.Split(kk, "_")[0]
tempMap[key] = Output{
Value: vv,
}
}
output[k] = tempMap
}
}
data, _ := json.MarshalIndent(&output, "", "\t")
fmt.Println(string(data))
}
I put some comments within the code just to separate sections. The first two parts are only supposed to define your input and output variables.
The section starting with // transformation is a good candidate to become a function but I preferred to leave it within the main function for demo purposes. Let me recap what's happens in the loop:
You range over the entries of your input variable
If the key has the suffix _model, you take it into consideration
You define a locally-scoped map (called tempMap) of type map[string]Output with the right number of elements that we're gonna add
You range over the v variable (that's why we're dealing with nested maps)
For each item, you're gonna add an entry to the tempMap
At the end of the nested loop, you add an entry to the parent map (output)
The last part is only for printing a beautiful JSON that can be easily read and checked.
Note that this code is simplified just to show off how to achieve your goal, adjust it before putting it into production.
Let me know if this helps, thanks!
I am new to golang. I have a json file with nested structures that I want to parse and populate.
I am trying to use mapstructure to try and populate. I am able to do it for simple structures. But when it comes to array for dictionaries(key:struct). The map[string]interface{} seems to fail with runtime error: index out of range.
I tried to do the following for the json example below.
type Window struct {
loc []int
wrtc string
label string
}
type View struct {
windows []Window
}
type Views struct {
views []View
}
type Desktop struct {
views []Views `mapstructure:views`
rotation_speed string `mapstructure:"rotationSpeed" json:rotationSpeed"`
}
func main() {
file, _ := ioutil.ReadFile("test.json")
data := Desktop{}
_ = json.Unmarshal([]byte(file), &data)
fmt.Println("data: ", data.views[0])
}
{
"desktop": {
"view": [{// configs for view1
"random_id1": {
"loc": [0,0,640,360],
"wrtc": "some string",
"label": "window 1"
},
"random_id213443": {
"loc": [640,360,1280,720],
"wrtc": "some string blah",
"label": "window 2"
},
// more windows with random ids....
},
{
// configs for view2...
}
],
"rotationSpeed": 30
}
Since the window id is random I am not able to define it in a struct.
I tried using mapstructure:",squash" but that seems to fail as well.
I appreciate any help with this.
#Burak Serdar is right
You don't need mapstructure. JSON unmarshaling can deal with this.
you code have many error, like struct, uppercase, 'views' etc..
follow is a demo:
package main
import (
"encoding/json"
"fmt"
)
var data = `
{
"desktop":{
"view":[
{
"random_id1_1":{
"loc":[
0,
0,
640,
360
],
"wrtc":"some string",
"label":"window 1"
},
"random_id1_2":{
"loc":[
640,
360,
1280,
720
],
"wrtc":"some string blah",
"label":"window 2"
}
},
{
"random_id2_1":{
"loc":[
0,
0,
640,
360
],
"wrtc":"some string",
"label":"window 1"
},
"random_id2_2":{
"loc":[
640,
360,
1280,
720
],
"wrtc":"some string blah",
"label":"window 2"
}
}
],
"rotationSpeed":30
}
}
`
type Window struct {
Loc []int
Wrtc string
Label string
}
type Desktop struct {
View []map[string]Window
Rotation_speed int `json:"rotationSpeed" mapstructure:"rotationSpeed"`
}
type Config struct {
Desktop Desktop
}
func main() {
c := Config{}
json.Unmarshal([]byte(data), &c)
fmt.Println("json.Unmarshal: ", c)
}
json.Unmarshal: {{[map[random_id1_1:{[0 0 640 360] some string window 1} random_id1_2:{[640 360 1280 720] some s
tring blah window 2}] map[random_id2_1:{[0 0 640 360] some string window 1} random_id2_2:{[640 360 1280 720] some
string blah window 2}]] 30}}
also you can use mapstructure by "remain", if you want View struct
type Window struct {
Loc []int
Wrtc string
Label string
}
type View struct {
Windows map[string]Window `mapstructure:",remain"`
}
type Desktop struct {
View []View
Rotation_speed int `json:"rotationSpeed" mapstructure:"rotationSpeed"`
}
type Config struct {
Desktop Desktop
}
func main() {
c2 := Config{}
m := map[string]interface{}{}
_ = json.Unmarshal([]byte(data), &m)
mapstructure.Decode(m, &c2)
fmt.Println("mapstructure: ", c2)
}
I have a nested structure definition flatened into a slice (this hypothesis is not negociable, I have to deal with it) :
type element struct {
Name string
Type string // can be basic type string (eg "uint8")
// or a definition.ID for nested struct
}
type definition struct {
ID string
Elements []element
}
type definitions []definition
allDefs := definitions{
{
ID: "root",
Elements: []element{
{
Name: "SubStruct",
Type: "sub1", // this is reference to another definition
},
{
Name: "VarU32",
Type: "uint32", // this is a basic type string representation
},
},
},
{
ID: "sub1",
Elements: []element{
{
Name: "VarU8",
Type: "uint8",
},
{
Name: "VarU16",
Type: "uint16",
},
},
},
}
And I would like to build the corresponding nested struct using a recursive method (don't know the real depth) :
func (defs definitions) getStruct(id string) interface{} {
for _, def := range defs {
if def.ID == id { // found a reference to definition
fields := []reflect.StructField{}
for _, e := range def.Elements {
s := defs.getStruct(e.Type)
fields = append(fields, reflect.StructField{
Name: e.Name,
Type: reflect.TypeOf(s),
Tag: "",
})
}
return reflect.New(reflect.StructOf(fields)).Interface()
}
}
// didn't found a reference to a definition, it should be a basic type
if id == "uint8" {
return reflect.ValueOf(uint8(0)).Interface()
}
if id == "uint16" {
return reflect.ValueOf(uint16(0)).Interface()
}
if id == "uint32" {
return reflect.ValueOf(uint32(0)).Interface()
}
// ignore the fact id could be anything else for this example
return nil
}
root := allDefs.getStruct("root")
// using spew to inspect variable : github.com/davecgh/go-spew/spew
spew.Dump(root)
// (*struct { SubStruct *struct { VarU8 uint8; VarU16 uint16 }; VarU32 uint32 })(0xc00004e400)({
// SubStruct: (*struct { VarU8 uint8; VarU16 uint16 })(<nil>),
// VarU32: (uint32) 0
// })
Then I want to be able to assign some variable's values :
rootValElem := reflect.ValueOf(root).Elem()
rootValElem.FieldByName("VarU32").SetUint(1)
spew.Dump(root)
// (*struct { SubStruct *struct { VarU8 uint8; VarU16 uint16 }; VarU32 uint32 })(0xc00004e400)({
// SubStruct: (*struct { VarU8 uint8; VarU16 uint16 })(<nil>),
// VarU32: (uint32) 1
// })
Setting root level variable value is OK, but I am unable to entering Sub level and assign any variable, no matter how I play with reflect ValueOf()/Elem()/Addr()..., here are some examples :
fieldSub := rootValElem.FieldByName("SubStruct")
// fieldSub.Kind() : ptr
// fieldSub.CanSet() : true
subVal := reflect.ValueOf(fieldSub)
// subVal.Kind() : struct
// subVal.CanSet() : false
fieldU16 := subVal.FieldByName("VarU16")
// fieldU16.Kind() : invalid
// fieldU16.CanSet() : false
fieldSubElem := fieldSub.Elem()
// fieldSubElem.Kind() : invalid
// fieldSubElem.CanSet() : false
fieldU16 := fieldSubElem.FieldByName("VarU16")
// panic: reflect: call of reflect.Value.FieldByName on zero Value
Thanks to mkopriva comment above, I understand now my mistake : fieldSub is a pointer and I should check if nil, then allocate the struct value before trying to get Elem() then Field :
fieldSub := rootValElem.FieldByName("SubStruct")
// fieldSub.Kind() : ptr
// fieldSub.CanSet() : true
// fieldSub.IsNil() : true
if fieldSub.IsNil() && fieldSub.CanSet() {
fieldSub.Set(reflect.New(fieldSub.Type().Elem()))
}
fieldU8 := fieldSub.Elem().FieldByName("VarU8")
// fieldSub.Kind() : uint8
// fieldSub.CanSet() : true
if fieldU8.CanSet() {
fieldU8.SetUint(8)
}
spew.Dump(root)
// (*struct { SubStruct *struct { VarU8 uint8; VarU16 uint16 }; VarU32 uint32 })(0xc00008a3f0)({
// SubStruct: (*struct { VarU8 uint8; VarU16 uint16 })(0xc0000ac430)({
// VarU8: (uint8) 8,
// VarU16: (uint16) 0
// }),
// VarU32: (uint32) 1
// })
I am getting this when I try to initialize a map in a struct. Here's the code:
//some code above
storageNodes[id].blocks = make(map[int64]Block)//error here
storageNodes[id].blocks[0] = generateBlockOfRandomFiles()
//some code below
//in a separate file
type StorageNode struct {
*Node
blocks map[int64]Block
}
What am I missing here?
Direct assignment to non-pointer map values is illegal in Go.
type Node struct{ /* ... */ }
type Block struct{ /* ... */ }
type StorageNode struct {
*Node
blocks map[int64]Block
}
// ...
storageNodes := map[int]StorageNode{123: {}}
storageNodes[123].blocks = map[int64]Block{987: {}} // illegal
Use pointers:
storageNodes := map[int]*StorageNode{123: {}}
storageNodes[123].blocks = map[int64]Block{987: {}}
fmt.Println(storageNodes[123].blocks) // block 987 is present
Or, use temporary variable and re-assign once modified:
storageNodes := map[int]StorageNode{123: {}}
sn := storageNodes[123] // read
sn.blocks = map[int64]Block{987: {}} // modify
storageNodes[123] = sn // write back to map
fmt.Println(storageNodes[123].blocks) // block 987 is present
I am trying to add an array of strings into the content part of a struct with the Id as the array index. I have the code working for one element, but get various errors when I try and add the loop. Any ideas are welcome. I am using Go.
func buildRequest(s []string) []*storepb.LongStoreRequest {
// ss:= []storepb.LongStoreRequest
// int32 i =0 stringv := s[0]
// for i := 0; i < len(s); i++ {
// println(i, apps[i])
ss := []*storepb.LongStoreRequest{
&storepb.LongStoreRequest {
Msg: &storepb.StoreMessage{
Content: stringv,
Account: "trevor3",
Parent: "parentrec",
Id: 0,
},
},
} // }
return ss
}
If I understand your description correctly, you want to build an array of LongStoreRequests, where each element corresponding to an item in the string array, with Id giving the array index. If that's really what you need, something like this should work:
ss := []*storepb.LongStoreRequest{}
for i,str:=range s {
ss=append(ss,&storepb.LongStoreRequest {
Msg: &storepb.StoreMessage{
Content: str,
Account: "trevor3",
Parent: "parentrec",
Id: i,
}})
}