How do you access this Go struct? [duplicate] - go

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])

Related

"invalid recursive type" and "illegal cycle in declaration of" [duplicate]

This question already has answers here:
invalid recursive type in a struct in go
(2 answers)
Closed 11 months ago.
Shortened example of the two custom types below. "Question" contains a "SavedQuestion" and "SavedQuestion" contains a "Question".
Errors:
1. illegal cycle in declaration of SavedQuestion
2. invalid recursive type Question
type Question struct {
ID int `json:"id"`
Name string `json:"name"`
QueryText string `json:"query_text"`
SavedQuestion SavedQuestion `json:"saved_question"`
}
type SavedQuestion struct {
ID int `json:"id"`
Index int `json:"index"`
Name string `json:"name"`
Packages PackageSpecList `json:"packages"`
QueryText string `json:"query_text"`
Question Question `json:"question"`
}
I'm modeling some types to consume a 3rd party API... The 3rd party API's objects are modeled this way. It seems perfectly normal that a "SavedQuestion" is a separate type that essentially contains a "Question" along with a bunch of other data about it... I can see the loop with a "Question" also containing a "SavedQuestion"... but that's what the API does. As you can see from the json tags I'm just trying to model exactly what the API is sending so I can marshal/unmarshal etc..
How do I make this work? I can make the "Question" in the "SavedQuestion" a pointer to a "Question" and the errors go away... however I don't know if I should or need to do that, or if it will actually work as the code is not yet complete enough to run a test...
New gopher confused...
Thanks for any input.
You cannot recursively include one struct within another for the simple reason that the size and memory layout of the struct becomes recursive. Size of Question is some data + size of (SavedQuestion), and size of SavedQuestion is size of some data + size of Question...
However, if you use pointers, the sizing problem is solved:
type Question struct {
ID int `json:"id"`
Name string `json:"name"`
QueryText string `json:"query_text"`
SavedQuestion *SavedQuestion `json:"saved_question"`
}
You need to make sure when to reference question.SavedQuestion, it is not nil. This will work just fine for marshaling/unmarshaling. When you unmarshal, if the JSON does not have a saved_question element, it'll be nil.

Struct type first line: _ struct{} [duplicate]

I am working with go, specifically QT bindings. However, I do not understand the use of leading underscores in the struct below. I am aware of the use of underscores in general but not this specific example.
type CustomLabel struct {
core.QObject
_ func() `constructor:"init"`
_ string `property:"text"`
}
Does it relate to the struct tags?
Those are called blank-fields because the blank identifier is used as the field name.
They cannot be referred to (just like any variable that has the blank identifier as its name) but they take part in the struct's memory layout. Usually and practically they are used as padding, to align subsequent fields to byte-positions (or memory-positions) that match layout of the data coming from (or going to) another system. The gain is that so these struct values (or rather their memory space) can be dumped or read simply and efficiently in one step.
#mkopriva's answer details what the specific use case from the question is for.
A word of warning: these blank fields as "type-annotations" should be used sparingly, as they add unnecessary overhead to all (!) values of such struct. These fields cannot be referred to, but they still require memory. If you add a blank field whose size is 8 bytes (e.g. int64), if you create a million elements, those 8 bytes will count a million times. As such, this is a "flawed" use of blank fields: the intention is to add meta info to the type itself (not to its instances), yet the cost is that all elements will require increased memory.
You might say then to use a type whose size is 0, such as struct{}. It's better, as if used in the right position (e.g. being the first field, for reasoning see Struct has different size if the field order is different and also Why position of `[0]byte` in the struct matters?), they won't change the struct's size. Still, code that use reflection to iterate over the struct's fields will still have to loop over these too, so it makes such code less efficient (typically all marshaling / unmarshaling process). Also, since now we can't use an arbitrary type, we lose the advantage of carrying a type information.
This last statement (about when using struct{} we lose the carried type information) can be circumvented. struct{} is not the only type with 0 size, all arrays with 0 length also have zero size (regardless of the actual element type). So we can retain the type information by using a 0-sized array of the type we'd like to incorporate, such as:
type CustomLabel struct {
_ [0]func() `constructor:"init"`
_ [0]string `property:"text"`
}
Now this CustomLabel type looks much better performance-wise as the type in question: its size is still 0. And it is still possible to access the array's element type using Type.Elem() like in this example:
type CustomLabel struct {
_ [0]func() `constructor:"init"`
_ [0]string `property:"text"`
}
func main() {
f := reflect.ValueOf(CustomLabel{}).Type().Field(0)
fmt.Println(f.Tag)
fmt.Println(f.Type)
fmt.Println(f.Type.Elem())
}
Output (try it on the Go Playground):
constructor:"init"
[0]func()
func()
For an overview of struct tags, read related question: What are the use(s) for tags in Go?
You can think of it as meta info of the type, it's not accessible through an instance of that type but can be accessed using reflect or go/ast. This gives the interested package/program some directives as to what to do with that type. For example based on those tags it could generate code using go:generate.
Considering that one of the tags says constructor:"init" and the field's type is func() it's highly probable that this is used with go:generate to generate an constructor function or initializer method named init for the type CustomLabel.
Here's an example of using reflect to get the "meta" info (although as I've already mentioned, the specific qt example is probably meant to be handled by go:generate).
type CustomLabel struct {
_ func() `constructor:"init"`
_ string `property:"text"`
}
fmt.Println(reflect.ValueOf(CustomLabel{}).Type().Field(0).Tag)
// constructor:"init"
fmt.Println(reflect.ValueOf(CustomLabel{}).Type().Field(0).Type)
// func()
https://play.golang.org/p/47yWG4U0uit

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)
}

What is the advantage of using a pointer to a string instead of a string in Go [duplicate]

This question already has answers here:
What does the asterisk do in "Go"?
(6 answers)
Closed 5 years ago.
Reviewing some go code I came across this:
Person struct {
Name *string `json:"name"`
}
and then some where I saw:
Animal struct {
Name string `json:"name"`
}
What is the advantage of the pointer here?
The * declares a pointer type. A pointer to a string is sometimes used when decoding JSON to distinguish the following JSON:
JSON value of the Name field
{ } nil
{name: ""} pointer to ""
Without the pointer, it's not possible to distinguish a missing value from a blank value in the decoded result.
If the application does not need to make this distinction, then use the second form shown in the question. It's more convenient.
* means pointer.
In your case, Name is a field of type pointer to string.
See http://www.golang-book.com/books/intro/8
The * is a pointer.
A pointer type denotes the set of all pointers to variables of a given
type, called the base type of the pointer. The value of an
uninitialized pointer is nil.
This is coming from the Go Spec. I would suggest reading it all.

Why do I get a "cannot assign" error when setting value to a struct as a value in a map? [duplicate]

This question already has answers here:
Accessing struct fields inside a map value (without copying)
(2 answers)
Closed 7 years ago.
New to Go. Encountered this error and have had no luck finding the cause or the rationale for it:
If I create a struct, I can obviously assign and re-assign the values no problem:
type Person struct {
name string
age int
}
func main() {
x := Person{"Andy Capp", 98}
x.age = 99
fmt.Printf("age: %d\n", x.age)
}
but if the struct is one value in a map:
type Person struct {
name string
age int
}
type People map[string]Person
func main() {
p := make(People)
p["HM"] = Person{"Hank McNamara", 39}
p["HM"].age = p["HM"].age + 1
fmt.Printf("age: %d\n", p["HM"].age)
}
I get cannot assign to p["HM"].age. That's it, no other info. http://play.golang.org/p/VRlSItd4eP
I found a way around this - creating an incrementAge func on Person, which can be called and the result assigned to the map key, eg p["HM"] = p["HM"].incrementAge().
But, my question is, what is the reason for this "cannot assign" error, and why shouldn't I be allowed to assign the struct value directly?
p["HM"] isn't quite a regular addressable value: hashmaps can grow at runtime, and then their values get moved around in memory, and the old locations become outdated. If values in maps were treated as regular addressable values, those internals of the map implementation would get exposed.
So, instead, p["HM"] is a slightly different thing called a "map index expression" in the spec; if you search the spec for the phrase "index expression" you'll see you can do certain things with them, like read them, assign to them, and use them in increment/decrement expressions (for numeric types). But you can't do everything. They could have chosen to implement more special cases than they did, but I'm guessing they didn't just to keep things simple.
Your approach seems good here--you change it to a regular assignment, one of the specifically-allowed operations. Another approach (maybe good for larger structs you want to avoid copying around?) is to make the map value a regular old pointer that you can modify the underlying object through:
package main
import "fmt"
type Person struct {
name string
age int
}
type People map[string]*Person
func main() {
p := make(People)
p["HM"] = &Person{"Hank McNamara", 39}
p["HM"].age += 1
fmt.Printf("age: %d\n", p["HM"].age)
}
The left side of the assignment must b "addressable".
https://golang.org/ref/spec#Assignments
Each left-hand side operand must be addressable, a map index expression, or (for = assignments only) the blank identifier.
and https://golang.org/ref/spec#Address_operators
The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array.
as #twotwotwo's comment, p["HM"] is not addressable.
but, there is no such definition show what is "addressable struct operand" in the spec. I think they should add some description for it.

Resources