-3

We have 3 types:

type A struct {
    B
    C
}
type B struct {
    x int
    y string
}
type C struct {
    z string
}

because of how fields and methods of an anonymous field are promoted, we can access fields of the anonymous field B in A like

var a A
a.x = 0

It is very obvious that type B & C embed in A, so we expect A to be equivalent to:

type D struct {
    x int
    y string
    z string
}

What did you expect to see?

We expect that we can write composite literals of type A like that:

a := A{x: 2}

What did you see instead?

This compile error:

unknown field 'x' in struct literal of type A

Our Question

Why isn't it possible to write composite literals for A in that way, as it would for the type D?

https://play.golang.org/p/uM5JkO5EvE

typetetris
  • 4,586
  • 16
  • 31
  • 1
    Possible duplicate of [nested struct initialization literals](https://stackoverflow.com/questions/19325496/nested-struct-initialization-literals) – Adrian Jul 10 '17 at 17:36
  • 1
    Possible duplicate of [Composite literal and fields from an embedded type](https://stackoverflow.com/questions/29979056/composite-literal-and-fields-from-an-embedded-type) – typetetris Jul 10 '17 at 17:40

2 Answers2

2

Rob 'Commander' Pike explained it here.

He wrote there:

It might one day, but as it stands the requirement to provide more information is more robust against changes in the data types.

If I understand and interpret that correctly, it is basically a safety measure for you. The compiler will yell at you, if the struct definition doesn't match the composite literal.

In your example, the definition of A might change -- in a later change (as in much later, like years) -- to:

    type A struct {
        x int
        y string
        z string
    }

later, but x, y and z might represent different things than before and therefore it is better, that you have to change all your literals to not get silently corrupt data of some kind.

That is a deliberate choice. The wording in the language specification is:

Promoted fields act like ordinary fields of a struct except that they cannot be used as field names in composite literals of the struct.

So you can use the field x of the field B as if it was a field of A except for composite literals.

And the types

type A struct {
    B
    C
}

and

type A struct {
    x int
    y string
    z string
}

really are two different things. The former contains two fields B and C, and the latter three fields x, y and z. The former just has some syntactic sugar to access the field x of the field B with a shorthand. So if a is a variable of the former type A, a.x is syntactic sugar for a.B.x.

typetetris
  • 4,586
  • 16
  • 31
1

You need to explicitly use B (and C) when initializing A:

a = A{B{x: 2}, C{}}

Oliver
  • 11,857
  • 2
  • 36
  • 42