Does whether or not a field is exported inside an anonymous struct make any difference? - go

Does exporting (or not exporting) a field in an anonymous struct in golang make any difference? In other words are the following two blocks of code different from each other in any way? Considering it's an anonymous struct, you can't use the struct outside the variable itself so I would assume the capital F doesn't make a difference when compiling (no compilation speed or run time memory differences).
Block 1:
var test = struct {
FieldOne string
FieldTwo string
} {
FieldOne: "some string",
FieldTwo: "some other string",
}
Block 2:
var test = struct {
fieldOne string
fieldTwo string
} {
fieldOne: "some string",
fieldTwo: "some other string",
}

Sure does, due to reflection. Try calling json.Marshal(test) after each of your declarations. In the first case, you will get {"FieldOne":"some string","FieldTwo":"some other string"}, but in the second case you will get {}. That's because the JSON marshaler only "sees" exported struct fields. More generally, even though the type of test doesn't have a name, doesn't mean that the type itself is inaccessible; it is accessible to anything with reflection.

Does exporting (or not exporting) a field in an anonymous struct in golang make any difference?
Of course, all the usual rules apply (you'll see the difference if you try to feed your struct to json.Marshal, for example).

Related

Why must I pass type to make function when variable is already declared?

I want use anonymous struct to do something.
var users []struct{
Name string `json:"name,omitempty"`
Age int
}
and I have to write the type again to set value
users = make([]struct{
Name string `json:"name,omitempty"`
Age int
}, 0, 10)
if I insist using anonymous struct, is there any way to make it more decent?
(if no, I wonder why golang design make function like this...)
Anonymous structs are handy for one-time use.
If you are using it more than once, then define a named struct type.
If you only use it within a single function, you can define the type within the scope of that particular function, so it's obvious that it cannot be used elsewhere:
func myfunc() {
type MyType struct {
Name string
}
m := MyType{Name: "Hello, World!"} // this type can only be used within this func
fmt.Println(m)
}
if I insist using anonymous struct, is there any way to make it more decent?
Yes, there is. Use :=:
users := make([]struct{
Name string `json:"name,omitempty"`
Age int
}, 0, 10)
Of course, this only works if you're calling make right after you're defining the variable. If these bits are separated by other code, this trick won't work for you.
But don't be afraid to name your types. That's generally a better approach anyway (with or without :=).

Why to use "redundant" keyword "struct" for types in Go?

I am a big fan of Golang, and very pleased to how the syntax of Go is designed. As a part of syntax philosophy, we have a rule as following: omit the things (keywords, characters etc.) if they are not needed actually.
For that reason instead of writing redundant colons:
for ; sum < 1000; {
sum += sum
}
You allowed to simply put:
for sum < 1000 {
sum += sum
}
notice how we omitted redundant semicolons
And there are lots of other cases where syntax is gratefully simplified.
But what about struct when we define type?
type Person struct {
name string
}
Why do we need to put struct keyword here?
Keywords are to determine intention, to clarify the exact choice of available options so a compiler knows how to do his job properly.
Will it be unclear and ambiguous if we simply put:
type Person {
name string
}
??
I believe there is a meaning for struct in the examples above
because compiler fails when type defined without struct keyword.
Please, explain me (and provide links) what else we can use instead of struct when we define some type.
Please, list available options from which we want to clarify to a compiler that things in curly brackets after type name are exactly parts of a struct and not something else (what else?).
Thanks.
It's not redundant. You can make types from existing types:
type MyType int
type MyType string
Or interfaces:
type Stringer interface {
String() string
}
This is covered in the Go tour and in the spec.
Types (may) not only appear in type declarations, but in countless other places, for example in function declarations.
Structs may be "used" anonymously, without creating a named type for them. For example, the following declaration is valid:
func GetPoint() struct{ x, y int } {
return struct{ x, y int }{1, 2}
}
Without having to use the struct keyword, a parsing ambiguity would arise in multiple uses. Let's say we want to create a function which returns an empty struct:
func GetEmpty() struct{} {
return struct{}{}
}
How would this look like without the struct keyword?
func GetEmpty2() {} {
return {}{}
}
Now if you're the compiler, what would you make out of this? Is this a function with the same signature as GetEmpty()? Or is this a function without a return value and an empty body (func GetEmpty2() {}) followed by a block which contains a return statement? The return statement would be another ambiguity, as it may return nothing which is followed by 2 empty blocks, or it may return an empty struct value which is followed by an empty block...
Now to avoid parsing ambiguity, we have to use the struct keyword when specifying struct types elsewhere (outside of type declarations), then why make it optional or disallow it in type declarations?
I think a consistent syntax is more important than grabbing all chances to reduce the language (syntax) to the minimum possible. That hurts readability big time. The for loop example you mentioned is not really a simplification, but rather the usage of different forms of the for loop.

Why would we use blank identifiers in Go?

I'm finding the use of the blank identifier a little hard to understand. I've looked at effective go and understand most of the use cases they describe but then looking at a tutorial I came across this in a route handler function:
var person Person
_ = json.NewDecoder(req.Body).Decode(&person)
in the first line we create a new empty variable of type Person (a struct previously defined) and then I assume that
&person is passing the person var in by reference,
to be filled with data by the Decode function
this function then goes on to perform a few more tasks before encoding and returning a json response.
Why do we need have the decode assigned to a blank identifier? Couldn't we just run json.NewDecoder(req.Body).Decode(&person) ? if we can't, why not?
I'm assuming you're learning golang and asking because you can't identify why this example used this practice.
As #JimB mentioned in comments, the example writer didn't need to do this they're simply ignoring the Error return.
The blank identifier _ can be used to strictly provide the keys in a struct too. See this for reference
Without enforcing
type SomeStruct struct {
FirstField string
SecondField bool
}
myStruct := SomeStruct{"", false}
Enforcing to mention the key for the value (Removes the dependency of ordering the values)
type SomeSturct struct {
FirstField string
SecondField bool
_ struct{}
}
// COMPILATION ERROR
myStruct := SomeSturct{"", false}
The above will give the error too few values in SomeSturct literal

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.

Nested properties for structs with unknown property names?

I'm using JSON to get some values into a variable from an external source.
I have a type like this that json.Unmarshal puts values into:
type Frame struct {
Type string
Value map[string]interface{}
}
var data Frame
After unmarshal, I can access a the type by: data.Type
but if I try doing something like:
if data.Type == "image" {
fmt.Printf("%s\n", data.Value.Imagedata)
}
The compiler complains about no such value data.Value.Imagedata.
So my question is, how do I reference properties in Go that I know will be there depending on some condition?
Doing this works:
type Image struct {
Filename string
}
type Frame struct {
Type string
Value map[string]interface{}
}
But that isn't very flexible as I will be receiving different Values.
json.Unmarshal will do its best to place the data where it best aligns with your type. Technically your first example will work, but you are trying to access the Value field with dot notation, even though you declared it to be a map:
This should give you some form of output:
if data.Type == 'image'{
fmt.Printf("%v\n", data.Value["Imagedata"])
}
… considering that "Imagedata" was a key in the JSON.
You have the option of defining the type as deeply as you want or expect the structure to be, or using an interface{} and then doing type assertions on the values. With the Value field being a map, you would always access the keys like Value[key], and the value of that map entry is an interface{} which you could type assert like Value[key].(float64).
As for doing more explicit structures, I have found that you could either break up the objects into their own types, or define it nested in one place:
Nested (with anonymous struct)
type Frame struct {
Type string
Value struct {
Imagedata string `json:"image_data"`
}
}
Seperate structs
type Frame struct {
Type string
Value value
}
type value struct {
Imagedata string `json:"image_data"`
}
I'm still learning Go myself, so this the extent of my current understanding :-).

Resources