-3

I'm facing with kind of strange shape when I'm using map in Golang. I searched about it with keywords "using two curly brackets when using struct" but couldn't find. What does it mean using like below 'struct{}{}'?

menu := map[string]interface{}{
    "icecream": "delicious",
    "eggs":struct {
        price float64 
    }{"chicken", 1.75}   }
Uranus_ly
  • 121
  • 1
  • 6
  • 3
    `struct{}{}` is the composite literal of the anonymous empty struct. Composite literals are explained here: https://go.dev/ref/spec#Composite_literals. Basically `struct{}` is the type definition, the second `{}` part makes the whole expression a composite literal, which, when evaluated, results in an instance of the type, i.e. in an instance of the empty struct. – mkopriva Dec 25 '22 at 13:57
  • 3
    Same as in `map[string]string{}` where `map[string]string` is the type and `{}` effectively initializes a non-nil instance of the `map[string]string` type. – mkopriva Dec 25 '22 at 14:02

1 Answers1

1

So let's break this down:

menu := map[string]interface{}{

Creates a variable called menu, of type map[string]interface{} (interface{} being any type that implements an interface with zero methods, so basically any type can be assigned). The last opening bracket is where the actual data contained within this map can be written, so:

foo := map[string]int{}
foo["bar"] = 1

Can be written as

foo := map[string]int{
   "bar": 1,
}

Now in your code, the first key-value pair is simple:

"icecream": "delicious",

The second one is the one you're unclear about:

"eggs":struct {
    price float64 
}{"chicken", 1.75}   }

Now this code is not going to compile, but let's change it to something that will:

"eggs":struct {
    kind  string
    price float64 
}{"chicken", 1.75}   }

What we're doing here is adding a key to the meny map (type map[string]any), and the value assigned to the key eggs is a struct. Specifically an anonymous struct with 2 fields:

struct {
    kind  string
    price float74
}

We want to set the fields to certain values, so we have to initialise this struct:

struct {
    kind  string
    price float64 
}{"chicken", 1.75}

This is the same as writing:

eggs := struct{
    kind  string
    price float64
}{
    kind:  "chicken",
    price: 1.75,
}

Or even:

type Egg struct {
    kind  string
    price float64
}

menu := map[string]any{
    "icecream": "delicious",
    "eggs": Egg{
        kind:  "chicken",
        price: 1.75,
    },
}

The thing that probably threw you off here is the omission of the fields when initialising the struct (which is considered bad form, and only really works if the order of the fields is preserved. Assuming something like this:

menu := map[string]any{
    "icecream": "delicious",
    "eggs": struct{
        kind  string
        price float64
    }{
        kind:  "chicken",
        price: 1.75,
    },
}

Then the following code won't work:

menu := map[string]any{
    "icecream": "delicious",
    "eggs": struct{
        kind  string
        price float64
    }{
        1.75, // first field in struct is expected to be a string
    },
}

But this will:

menu := map[string]any{
    "icecream": "delicious",
    "eggs": struct{
        kind  string
        price float64
    }{
        price: 1.75,
    },
}

Overall, it's not that common to see things like this outside of tests, or types that are used to (un) marshal large data-sets where you don't need to use/separate subsets of the data. I think the last time I've used this kind of anonymous structs in code was when I had to receive and pass on chunks of XML data, but do no processing on it, I would create types like:

type XMLInput struct {
    // fields of data I actually needed to use
    Details struct {
        // fields that I needed to make sure were set, but didn't do any processing on, so I didn't need a usable type
    } `xml:"whatever_tag"`
}
Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149