How do I make sure that the fileds of the root struct get parsed first and then the fields of embedded struct gets parsed - go

I have the struct as follows:-
type Inner struct {
FooInner string `json:"fooInner"`
BarInner string `json:"barInner,omitempty"`
}
type Root struct {
Inner
Foo string `json:"foo"`
Bar string `json:"bar"`
}
I want the fields of "Root" struct to be parsed first and then the fields of the "Inner" struct. But here the fields of Inner struct is getting parsed first.

If you are asking about JSON marshaling (which is not parsing) and want fields marshaled in a certain order, a marshaler will typically marshal fields in their index order & recurse any embedded structs along the way. Struct field indices - as seen by the reflect package that json.Marhsal uses - are defined by their order of appearance in your code.
So put the fields you want first - and any embedded structs later:
type Root struct {
Foo string `json:"foo"`
Bar string `json:"bar"`
Inner // <- move this last
}
Playground Example
b, _ := json.Marshal(Root{})
{"foo":"","bar":"","fooInner":""}

Related

Read top level struct tags

How to get the tags from a struct field in Go? I have a nested struct which I want to pass as an argument to another function and read the tags there. I know that by accessing it as a field is possible, but I am searching for a way to it.
type MyStruct struct {
Nested struct{} `bson:"nested"`
}
func main() {
val := reflect.ValueOf(MyStruct{})
val.Type().Field(0).Tag.Get("bson") // I want to avoid this
val := reflect.ValueOf(MyStruct{}.Nested)
val.Tag???
}
The tag you want to access belongs to MyStruct. If you pass the value of the Nested field, a copy is made which will be completely detached from MyStruct. There's no way to tell if the value passed originates from a field of MyStruct or from another struct, or from any other source (e.g. from a composite literal). So this is not possible.

Synonymous struct field and method name for interface

I'm building a type structure that represents some devices on my network. There are lots of types of these devices, such as:
type Foo struct { ... }
type Bar struct { ... }
type Spam struct { ... }
but they all share a few common fields, one of which is IP. I'd like to define Device as an interface so I can group these together logically
type Device interface {
IP() string
...
}
type LogicalGrouping struct {
Devices []Device
...
}
but I'm running into an error with overlapping names.
func (f *Foo) IP() string { return f.IP } // same method name as field name
I can rename either the field or the method or both, but surely this must be a common use case -- grouping structs by the fields they have in common? Is there an idiomatic solution here?
The general rule of thumb is that interfaces define behaviours and fields define data.
The problem here is that you are using an interface to access data in fields. On it's own that's not necessarily a bad thing. But you might want to reconsider how to structure your code so that you don't get this collision.
The first question I would as is:
"Why do you need to export the field IP if the struct defines an IP() method that has access to it?"
You could make the struct field unexported i.e. ip not IP, and then in the place you are using struct.IP, use struct.IP() instead.
The second question is:
"If you have structs such as foo, bar, spam and they all share common fields, why not use composition to deduplicate the definition of those shared fields."
This would probably only work if you are really only after the data that's inside the struct, I would generally advocate for using interfaces in all cases.
If you have the following structs:
type Foo struct {
IP string
A string
B string
}
type Bar struct {
IP string
A string
B string
}
type Spam struct {
IP string
A string
B string
}
You could use a new struct to represent the fields they have in common, and anonymously compose that inside:
type Inner struct {
IP string
A string
B string
}
type Foo struct {
Inner
}
type Bar struct {
Inner
}
type Spam struct {
Inner
}
In the function call where you were using struct.IP(), accept an Inner and call it with struct.Inner. You will still have access to struct.IP even though IP is defined inside Inner.
You also may consider option to have ip field and GetIP & SetIP methods (or IP & SetIP accordingly to this doc) - it's clear, concise and simple.

Using (sub)struct located in other package in Datastore

I haven't been able to find any information related to this.. let's say you call an API and save the resulted json into a struct in package Foo, like this:
package foo
type FooData struct {
A string `json:"c"`
B int `json:"c"`
C int64 `json:"c"`
}
Then you have your own model package:
package bar
import (
"github.com/bla/bla/foo"
)
type BarData struct {
A float
Foo foo.FooData
}
Is this possible? Is there anything negative about doing it this way? The reason is the structs are over a hundred lines, so I feel it would be wasteful to duplicate it.
Also, what if I only want to index in B? Then I can just change it to:
type FooData struct {
A string `datastore:",noindex" `json:"c"`
B int `json:"c"`
C int64 `datastore:",noindex" `json:"c"`
}
?
Edit: Just to make it clear, my intention is to save the BarData struct in Datastore
The Go Datastore package has some documentation relating to this - https://cloud.google.com/appengine/docs/standard/go/datastore/reference#hdr-Structured_Properties
"Structured Properties
If the struct pointed to contains other structs, then the nested or embedded structs are flattened. For example, given these definitions:
type Inner1 struct {
W int32
X string
}
type Inner2 struct {
Y float64
}
type Inner3 struct {
Z bool
}
type Outer struct {
A int16
I []Inner1
J Inner2
Inner3
}
then an Outer's properties would be equivalent to those of:
type OuterEquivalent struct {
A int16
IDotW []int32 `datastore:"I.W"`
IDotX []string `datastore:"I.X"`
JDotY float64 `datastore:"J.Y"`
Z bool
}
If Outer's embedded Inner3 field was tagged as datastore:"Foo" then the equivalent field would instead be: FooDotZ bool datastore:"Foo.Z".
If an outer struct is tagged "noindex" then all of its implicit flattened fields are effectively "noindex"."
So there shouldn't be any issues with you storing nested structs, just be aware that they will be flattened in datastore. It also mentions the no indexing, saying any field inherits a "noindex" from its parent struct. I don't see why your "noindex" tagging of the inner fields wouldn't work.

What are the second pair of braces in this Golang struct?

var cache = struct {
sync.Mutex
mapping map[string]string
} {
mapping: make(map[string]string),
}
This looks like a struct with an embedded field sync.Mutex but I can't get my head around the second set of braces. It compiles and executes but what's up? Why does the label on the make instruction matter (it does) and the comma? Thanks...
The example you have is equivalent to:
type Cache struct {
sync.Mutex
mapping map[string]string
}
cache := Cache{
mapping: make(map[string]string),
}
Except in your example you do not declare a type of Cache and instead have an anonymous struct. In your example, as oppose to my Cache type, the type is the entire
struct {
sync.Mutex
mapping map[string]string
}
So think of the second pair of braces as the
cache := Cache{
mapping: make(map[string]string),
}
part.
make is a built in function that works similarly to C's calloc() which both initialize a data structure filled with 0'd values, in Go's case, certain data structures need to be initialized this way, other's (for the most part structs) are initialized with 0'd values automatically. The field there is needed so that the compiler now's cache.mapping is a empty map[string]string.
The comma there is part of Go's formatting, you can do Cache{mapping: make(map[string]string)} all on one line, but the moment the field's assignment is on a different line than the opening and closing braces, it requires a comma.
This is called a "struct literal" or an "anonymous struct" and is, in fact, how you always create structs in Go, it just may not be immediately obvious since you might be used to creating new types for struct types to make declaring them a bit less verbose.
An entire struct definition is actually a type in Go, just like int or []byte or string. Just as you can do:
type NewType int
var a NewType = 5 // a is a NewType (which is based on an int)
or:
a := 5 // a is an int
and both are distinct types that look like ints, you can also do the same thing with structs:
// a is type NewType (which is a struct{}).
type NewType struct{
A string
}
a := NewType{
A: "test string",
}
// a is type struct{A string}
a := struct{
A string
}{
A: "test string",
}
the type name (NewType) has just been replaced with the type of the struct itself, struct{A string}. Note that they are not the same type (an alias) for the purpose of comparison or assignment, but they do share the same semantics.

encoding/xml handle unmapped elements

From http://golang.org/pkg/encoding/xml/#Unmarshal
If the XML element contains a sub-element that hasn't matched any of the above rules and the struct has a field with tag ",any",
unmarshal maps the sub-element to that struct field.
I'm having trouble getting the remainder of an XML envelope into my struct (to show that I have an incomplete mapping)
http://play.golang.org/p/mnFqAcguJQ
I know you can use exactly this method with bson.M from the mgo packages using ,inline - but it looks like map[string]interface{} isn't the answer here.
EDIT:
After some additional playing, I've found what I believe to be some additional unexpected behavior.
Switching to []string as a type starts to accept input, but no key/value pairs: http://play.golang.org/p/wCAJeeQa4m
I also planned on adapting encode/xml in order to parse html. I do not see in the documentation that if an element exists more than once, it will save the last instance of it, rather than erroring out: http://play.golang.org/p/0MY__R-Xi3
Here: http://play.golang.org/p/iY8YlxYym0
Since c is something concrete, it shouldn't use ",any", hence it should have a struct definition. C itself contains a list of arbitrary tags, hence it should contain an []Tag xml:'",any"'... now to capture the Tag itself, you need xml.Name to get the tag name and something with ",innerxml".
Finally the result is this:
const xmlString = `<foo><a>1</a><b>2</b><c><c1>3</c1><c2>4</c2></c></foo>`
type Foo struct {
A int `xml:"a"`
B int `xml:"b"`
C Extra `xml:"c"`
}
type Extra struct {
Items []Tag `xml:",any"`
}
type Tag struct {
XMLName xml.Name
Content string `xml:",innerxml"`
}
Or the shorter version:
type Foo struct {
A int `xml:"a"`
B int `xml:"b"`
C struct {
Items []struct {
XMLName xml.Name
Content string `xml:",innerxml"`
} `xml:",any"`
} `xml:"c"`
}
For HTML there is go.net/html. Using xml parser for html will be complicated.

Resources