8

From Chapter 7 of GOPL (Section 7.6), I noticed this line:

var tracks = []*Track{
     {"Go", "Delilah", "From the Roots Up", 2012, length("3m38s")},
     {"Go", "Moby", "Moby", 1992, length("3m37s")},
     {"Go Ahead", "Alicia Keys", "As I Am", 2007, length("4m36s")},
     {"Ready 2 Go", "Martin Solveig", "Smash", 2011, length("4m24s")},
}

I was kind of confused by how it initialized the slice of Track pointers. So later I tried the following example:

type Ex struct {
    A, B int
}

a := []Ex{Ex{1, 2}, Ex{3, 4}}
b := []Ex{{1, 2}, {3, 4}}
c := []*Ex{&Ex{1, 2}, &Ex{3, 4}}
d := []*Ex{{1, 2}, {3, 4}}
e := []*Ex{{1, 2}, &Ex{3, 4}}

I found all of the 5 cases are okay with no errors. The {1, 2} seems to be a structure called "anonymous struct", but it confuses me since it works fine even when I am trying to fill in *Ex pointers instead of Ex struct.

Furthermore, when I try the following code, it complains syntax error:

f := []*Ex{&{1, 2}, &{3, 4}} // Syntax Error!

Can somebody help explain what is actually going on in these cases?

Kevin Qian
  • 2,532
  • 1
  • 16
  • 26
  • 3
    The first two examples you have aren't pointers. The last three are all the same, with the knowledge that the type can be elided from composite literals when it can be inferred. Are you looking for the [Composite Literals spec](https://golang.org/ref/spec#Composite_literals)? – JimB Aug 11 '17 at 16:29
  • 1
    @JimB Thanks! The material is exactly what I needed for understanding. It seems that the GOPL book missed the topic (or probably I missed the chapters that are actually mentioning it...) – Kevin Qian Aug 11 '17 at 16:41

2 Answers2

6

I think anonymous isn't quite the correct word here. The struct has a name, "Track" or "Ex". But you are initializing it with a shortcut:

f := []<type>{{...}, {...}}

is roughly the same as:

f := []<type>{<type>{...}, <type>{...}}

But it's a little smarter than blind string replacement. If <type> is a pointer like *Ex or *Track, it also automatically initializes correctly:

f := []*<type>{{...}, {...}} // is the same as...
f := []*<type>{&<type>{...}, &<type>{...}}

It works the same for maps:

f := map[string]*<type>{"a": {...}, "b": {...}} // is the same as...
f := map[string]*<type>{"a": &<type>{...}, "b": &<type>{...}}

For further clarification, anonymous structs are ones that have no separate type definition. These are anonymous types, but not anonymous structs. An anonymous struct is a struct with no associated type definition. This syntax of initializing values without referring to the type is essential to making the manageable:

f := []struct{
    A, B int
}{
    {1, 2}, {3, 4}
}
// or with pointers...
f := []*struct{
    A, B int
}{
    {1, 2}, {3, 4}
}

Here the struct within the list has no type definition, so it is anonymous. And thanks to the initialization shorthand, that's fine - I don't need a name to initialize it.

tschundler
  • 2,098
  • 1
  • 14
  • 15
0

Please give more detail on your structure definition of Ex.

But, if Ex is implemented as this:

type Ex struct {
    t interface{}
    o interface{}
}

you don't give a pointer of anonymous struct because, the definition it's not know.

Also you can't do:

variable := new({1, 2})
// or
variable := {1, 2}

When you do:

b := []Ex{{1, 2}, {3, 4}}
// you create slice of Ex with two Ex struct
// so b := []Ex{Ex{t:1,o:2}, Ex{t:3, o:4}}

contrariwise:

f := []*Ex{&{1, 2}, &{3, 4}}
// you create slice of unknow definition type
// f = []Ex{Ex{t: addressOfUnknowType, o: addressOfUnknowType}}

I hope help you