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
Related
I am having a json as
{
"fields": ["time","id","status","customerId","additionalDetail"],
"pageInfo": {"start": 0, "rows": 1000}
}
I wanted to Marshal my structure to above json and create the structure as below -
type RBody struct {
Fields []string `json:"fields"`
PageInfo struct {
Start int `json:"start"`
Rows int `json:"start"`
} `json:"pageInfo"`
}
I am having trouble in initializing the above structure. I am not sure how to initialize the anonymous struct in below fashion :
bd := RBody {
Fields : []string{"time","id","status","customerId","additionalDetail"},
PageInfo : ???
}
I worked around this by creating a separate structure for page info and attaching that with parent struct. However there's got to be some way to perform the initialisation of the anonymous nested struct, in the same way I did with Fields (string slice) above. Can anyone redirect me to some guide to do that ?
This works, but it is ugly:
bd := RBody { Fields : []string{"time","id","status","customerId","additionalDetail"},
PageInfo : struct {Start int `json:"start"`
Rows int `json:"rows"`} {Start:1,Rows:2}}
I suggest you either name the anonymous struct, or initialize Fields in the declaration, and PageInfo using assignments later.
Now I'm working on GO RPC, I'm using gRPC+Protobuf. And I follow openconfig's data struct, so I could NOT redesign.
I need to fill protobuf struct and Marshal it and send it out, and then client will Unmarshal it and read datas.
My protobuf file(xxx.pb.go) is complicated, for example, just like this:
type ObjBase struct {
a *ObjChildAlice,
b *ObjChildBob,
... // there are many variables like ObjChildCheer, ObjChildDog ...
}
type ObjChildAlice struct {
child *ObjChildChild,
}
type ObjChildBob struct {
child *ObjChildChild,
}
// there are many types like ObjChildCheer, ObjChildDog ...
type ObjChildChild {
int i,
}
In server side, I need to fill ObjBase and send it out, this is my task:
// Code 1
func () {
init ob with ObjBase
if DataBase has Alice {
fill ob.a with ObjChildAlice
}
if DataBase has Bob {
fill ob.a with ObjChildBob
}
// there are many if..else.. DataBase has Cheer...
return ob
}
So I code like this first:
// Code 2
func () {
ob := new(ObjBase)
oba := new(ObjChildAlice)
obb := new(ObjChildBob)
if DataBase has Alice {
ob.a = oba
}
if DataBase has Bob {
ob.b = obb
}
...
return ob
}
But this code could NOT work, as I check member of ob.a and ob.b are all zero.
So I change like this:
// Code 3
func () {
if DataBase has Alice && DataBase has Bob {
ob := &ObjBase{
a: &ObjChildAlice{},
b: &ObjChildBob{},
}
} else if DataBase has Alice && NOT DataBase has Bob {
ob := &ObjBase{
a: &ObjChildAlice{},
}
} else if ...
return ob
}
This works. But in database, there are kinds of variables like Alice, Bob, Cheer, Dog ... It's impossible to use if..else.. to do this work.
So I have questions:
Why ob'member in Code2 is zero?
is there any way to set Go struct's member object dynamically?
Please take a look at this doc which talks the Go generated code for protobufs. https://developers.google.com/protocol-buffers/docs/reference/go-generated
You should be able to set a protobuf message field in the generated code by directly accessing the corresponding member field (which is exported).
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,
}})
}
I have a meal struct that "appends" another struct, except I want to add another struct "mealComponents".
type mealMain struct {
*model.Meal
Components []mealComponent `json:"components"`
}
type mealComponent struct {
*model.MealComponent
}
Where *model.Meal is as follows
type Meal struct {
ID int64 `json:"id"`
}
What I want is basically for "mealMain" struct to act like "Meal" struct, so that I can assign values and somehow append mealComponent as child (or maybe this is not a good idea? I'm open to suggestions)
However when I do something like this
var meal mealMain
meal.ID = 1
It throws runtime error: invalid memory address or nil pointer dereference at meal.ID assignment.
But if I do it like this:
type mealMain struct {
MealMain *model.Meal `json:"meal_main"`
Components []mealComponent `json:"components"`
}
Then assign it this way:
var meal mealMain
meal.mealMain.ID = 1
It works properly, but I have the return json even deeper like this:
{
"MealModel": {
"id": 1
}
}
What I want is this:
{
"id": 1
}
Note: I want to avoid changing the model.
If you don't want to change the model:
var meal = mealMain{
Meal: &Meal{},
}
meal.ID = 1
The point is that in the following struct *Meal is set to nil if you don't initialize it.
type mealMain struct {
*Meal
Components []mealComponent `json:"components"`
}
I'd probably create a function to never have to worry about the correct initialization ever again:
func newMealMain() mealMain {
return mealMain{
Meal: &Meal{},
}
}
Then your code would be:
var meal = newMealMain()
meal.ID = 1
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.