Convert interface{} to struct in Golang - go

I am very new to Go and am trying to get my head around all the different types and how to use them. I have an interface with the following (which was originally in a json file):
[map[item:electricity transform:{fuelType}] map[transform:{fuelType} item:gas]]
and I have the following struct
type urlTransform struct {
item string
transform string
}
I have no idea how to get the interface data into the struct; I'm sure this is really stupid, but I have been trying all day. Any help would be greatly appreciated.

Decode the JSON directly to types you want instead of decoding to an interface{}.
Declare types that match the structure of your JSON data. Use structs for JSON objects and slices for JSON arrays:
type transform struct {
// not enough information in question to fill this in.
}
type urlTransform struct {
Item string
Transform transform
}
var transforms []urlTransform
The field names must be exported (start with uppercase letter).
Unmarshal the JSON to the declared value:
err := json.Unmarshal(data, &transforms)
or
err := json.NewDecoder(reader).Decode(&transforms)

From your response : [map[item:electricity transform:{fuelType}] map[transform:{fuelType} item:gas]].
As you can see here this is a an array that has map in it.
One way to get the value from this is :
values := yourResponse[0].(map[string]interface{}). // convert first index to map that has interface value.
transform := urlTransform{}
transform.Item = values["item"].(string) // convert the item value to string
transform.Transform = values["transform"].(string)
//and so on...
as you can see from the code above I'm getting the the value using map. And convert the value to the appropriate type in this case is string.
You can convert it to appropriate type like int or bool or other type. but this approach is painful as you need to get the value one bye one and assign it your your field struct.

Related

Get a FieldDescriptor without hard-coding the field name (proto message)

Given the following proto message
message MyMsg {
string my_field = 1;
string your_field=2;
}
...the protoreflect package can be used to get a descriptor for each field
protoMessage := myMsg.ProtoReflect()
messageDescriptor := protoMessage.Descriptor() // protobuf type information
fieldDescriptors := messageDescriptor.Fields() // list of field declarations
Getting a field descriptor for a specific field is trivial
fieldDescriptor := fieldDescriptors.ByTextName("my_field") // describes a field
Can this be achieved without hard-coding the field name "my_field"? I guess it would be nice to use the generated code to refer to the field I'm interested in. Something like (not working code)
fieldDescriptor := fieldDescriptors.ByTextName(pb.MyMsg.MyField) // describes a field
This way, if the field name changes, it will be caught at compile time, or even from static analysis by an IDE.
The FieldDescriptors type has three methods for getting a field descriptor by name:
ByName(s Name)
ByJSONName(s string)
ByTextName(s string)
ByJSONName and ByTextName both require hard-coded field names (as strings), and by ByName accepts a Name which is type'd to a string. The upshot is, I don't see anything in the protoreflect package that points to a solution.
Context
Field masks are the recommended way to support partial resource updates. It's trivial to iterate over the masks provided in a field mask
protoMessage := myMsg.ProtoReflect()
messageDescriptor := protoMessage.Descriptor() // protobuf type information
fieldDescriptors := messageDescriptor.Fields() // list of field declarations
// iterate over the field paths in the field mask
for _, p := range mask.GetPaths() {
// find the field descriptor for the field path
fieldDescriptor := fieldDescriptors.ByTextName(p)
if fieldDescriptor == nil {
// field descriptor cannot be found for the field path
return
}
// great, the field path points to a field, let's use it
switch p {
case "my_field":
// the client wants to update MyMsg.my_field
case "your_field":
// the client wants to update MyMsg.your_field
}
}
The problem is, in order to actually update the correct field in MyMsg, it's necessary to hard-code the field name in the switch statement.
The interface has ByNumber too
I assume (I've not used the method) that you could give this 1 from your example.
And Get, of course so that you can enumerate all of the FieldDescriptors.
I think it's not unreasonable to want to reflect (!) the generated (struct) types and enumerate across them but it feels like turtles-all-the-way-down.
It may help solicit other answers if you could present the problem that you're unable to solve without the desired method?

How do you access this Go struct? [duplicate]

This question already has an answer here:
Strange type definition syntax in Golang (name, then type, then string literal)
(1 answer)
Closed 1 year ago.
I'm trying to make sense of this Go struct:
type ListClustersOutput struct {
_ struct{} `type:"structure"`
// A list of all of the clusters for your account in the specified Region.
Clusters []*string `locationName:"clusters" type:"list"`
// The nextToken value to include in a future ListClusters request. When the
// results of a ListClusters request exceed maxResults, you can use this value
// to retrieve the next page of results. This value is null when there are no
// more results to return.
NextToken *string `locationName:"nextToken" type:"string"`
}
Looking at the docs: https://golangdocs.com/structs-in-golang#defining-a-struct-in-go
it gives an example:
type Fruit struct {
name string
}
which seems very different.
In the more complex code, I assume this Clusters []*string `locationName:"clusters" type:"list"` is equivalent to name string but struggling to unpack it.
I'm struggling to find much out about type: "list" - most of the examples seem to refer to slices. Why are they using a list?
what is a locationName?
how do you access the first element of the list in that struct?
Note, for this last question, if I use result.Clusters[0] (where result is of this struct type) I get a pointer. E.g.
fmt.Println("Result: ", result.Clusters[0])
Result: 0xc000372260
How do I dereference it?
Looking at this:
How does pointer dereferencing work in Go?
it seems you need an asterisk or an ampersand. Not clear which one you use or whether you tack it on the beginning or the end.
You are struggling with struct tags.
In your code:
Clusters []*string `locationName:"clusters" type:"list"`
The Clusters field has a type ([]*string) and the rest of the declaration are 2 struct tags that you should take the value(s) of tags using struct tag.
Here's how you access it:
fmt.Println("Result: ", *result.Clusters[0])

Getting error while access the struct type of array element as undefined (type []ParentIDInfo has no field or method PCOrderID)

I am new to golang and I have one issue which I think community can help me to solve it.
I have one data structure like below
type ParentIDInfo struct {
PCOrderID string `json:"PCorderId",omitempty"`
TableVarieties TableVarietyDC `json:"tableVariety",omitempty"`
ProduceID string `json:"PRID",omitempty"`
}
type PCDCOrderAsset struct {
PcID string `json:"PCID",omitempty"`
DcID string `json:"DCID",omitempty"`
RequiredDate string `json:"requiredDate",omitempty"`
Qty uint64 `json:"QTY",omitempty"`
OrderID string `json:"ORDERID",omitempty"`
Status string `json:"STATUS",omitempty"`
Produce string `json:"Produce",omitempty"`
Variety string `json:"VARIETY",omitempty"`
Transports []TransportaionPCDC `json:"Transportaion",omitempty"`
ParentInfo []ParentIDInfo `json:"ParentInfo",omitempty"`
So I have issue to access the PCOrderID which inside the []ParentIDInfo . I have tried below however I getting error as "pcdcorder.ParentInfo.PCOrderID undefined (type []ParentIDInfo has no field or method PCOrderID)"
keyfarmercas = append(keyfarmercas, pcdcorder.ParentInfo.PCOrderID)
Any help will be very good
Thanks in advance
PCDCOrderAsset.ParentInfo is not a struct, it does not have a PCOrderID field. It's a slice (of element type ParentIDInfo), so its elements do, e.g. pcdcorder.ParentInfo[0].PCOrderID.
Whether this is what you want we can't tell. pcdcorder.ParentInfo[0].PCOrderID gives you the PCOrderID field of the first element of the slice. Based on your question this may or may not be what you want. You may want to append all IDs (one from each element). Also note that if the slice is empty (its length is 0), then pcdcorder.ParentInfo[0] would result in a runtime panic. You could avoid that by first checking its length and only index it if its not empty.
In case you'd want to add ids of all elements, you could use a for loop to do that, e.g.:
for i := range pcdorder.ParentInfo {
keyfarmercas = append(keyfarmercas, pcdcorder.ParentInfo[i].PCOrderID)
}

Is there a way to have a dynamic type slice in Go?

I have a standard response built in PHP for microservices that I want to replicate in Go.
In particular, the "data" element of the response array can have anything.
Example
$response['data'] = [];
$response['data']['entities'] = [ objects that implements toArray() ]
$response['data']['quantity'] = 1
Problem is that Data differs per endpoint.
So one option I was thinking is in each endpoint (controller, action, etc) declare a Data struct that I would use in the StandardResponse.Data struct.
But how can I achieve that? Using interfaces?
Sorry I am new to Go.
An interface{} is one way to do it. Something like:
type StandardResponse struct {
Error bool
ErrorMsg string
Data interface{}
}
Marshaling this to JSON will work assuming the underlying type of interface{} supports it.

How to insert a struct with nil field to mongo?

I am trying to insert a struct to mongo. Firstly I get the data from an API as JSON and assign the data to a struct. Some fields might be nil. After that I insert the struct to mongoDB. So the problem I get is that when inserted, all the fields are initialized. For example I have a struct like this:
type VirtualMachine struct {
VirtualMachineID utils.SUUID `bson:"VirtualMachineID"`
Cdroms []*VM.VirtualMachineCdrom `bson:"Cdroms"`
CpuAllocatedMHz int `bson:"CpuAllocatedMHz"`
Name string `bson:"Name"`
}
If I get Json data like this
{
"VirtualMachineID":'16as4df663a',
"Cdroms":null,
"CpuAllocatedMHz":1666,
"Name":'VMName'
}
after I put it to mongo, the null field becomes an empty array. I need to avoid that. 'omitempty' did not help because it skips the field as well if the provided field happens to be an empty array and not null.
Firstly I thought it was because of the pointers, but later I found that the same happens to all data types. Shortly, if its nil, mgo converts it to its zero value.
I think I am missing something here, because it would be weird if mgo converts all nil values to their zero values by design.
Try *[]*VM.VirtualMachineCdrom (or just *[]VM.VirtualMachineCdrom if you don't actually need the elements to be pointers). A nil slice == a zero length slice, but a nil pointer to a slice does not.

Resources