atc0005 / learn

Various topics that I want to learn more about, either for professional development or for my own use
0 stars 0 forks source link

Golang | Structs | struct field members #25

Open atc0005 opened 5 years ago

atc0005 commented 5 years ago

From atc0005/Learn-Go-in-3-Hours/classwork/ch4/structs/main.go@99b123b3ac8bb42b7ab9787399f37a04d90206f2:

package main

import "fmt"

type Foo struct {

    // due to uppercase leading character, this is "public"
    // Go encourages public fields for simple data structures
    A int
    b string
}

type Bar struct {
    C string

    // declare field of type Foo (which is itself a struct)
    F Foo
}

type Baz struct {
    D string

    // embedded struct
    Foo
    // embedding is a very useful way to reuse a struct across multiple
    // structs. Imagine defining an address struct, or a person struct, and
    // embedding it into many different types avoiding a lot of nested dotted
    // paths through struct references. While embedding might look like
    // inheritance it isn't, embedding provides delegation. Baz is not a
    // subtype of foo, it just contains a foo as a field.
    //
    // From "Introducing Go":
    //
    // Their example is a Person struct and an Android struct which embeds
    // the Person struct (aka, an "anonymous" field). This is referred to as
    // an "is a" relationship.
}

func main() {

    f := Foo{A: 10, b: "Hello"}

    // we use the initialized 'f' struct as a value for the 'F' field below
    b1 := Bar{C: "Fred", F: f}

    // we need to use the intermediate struct 'F' in order to access 'A'
    // Q: Why?
    // Q: Is this because the struct 'F' is bundled within the enclosing struct
    //    without "collapsing" the field values?
    fmt.Println(b1.F.A)

    b2 := Baz{D: "Nancy", Foo: f}

    // the intermediate struct is not needed to reference 'A' from the
    // embedded struct.
    // Q: Are the embedded struct fields "collapsed" into the enclosing struct?
    // A: According to "Introducing Go", this is an "is a" relationship with
    //    their example being a 'Person' struct and an 'Android' struct which
    //    embeds the 'Person' struct (aka, an "anonymous" field). This reflects
    //    that an Android "is a" Person, so naturally has the same fields and
    //    (presumably in later code) the same methods?
    fmt.Println(b2.A)

    // declare and initialize 'f2' struct, set values equal to b2.Foo struct
    var f2 Foo = b2.Foo
    fmt.Println(f2)

}
atc0005 commented 4 years ago

Snippet:

I'm assuming your Employee struct is now of the form

type Employee struct { Person number int }

If so, as described in Effective Go, "Constructors and composite literals", you can construct structs using { } syntax in two ways:

  1. Providing the values for each (and every) field in order, eg.

    dude := Employee{ Person{"Me"}, 1 }

  2. Or, by using field:value initializers for any number of fields in any order, eg.

    dude := Employee{ Person:Person{"Me"}, number:1 } or dude := Employee{ number:1, Person:Person{"Me"} } or dude := Employee{ Person:Person{"Me"} } (number gets default value of 0)

But, you can't mix and match those styles, as you've attempted to do.

atc0005 commented 4 years ago

I ran into this again today while working on atc0005/go-ezproxy#13. I started off trying something like this:

result := TerminateUserSessionResult{
    UserSession: {
        SessionID: session.SessionID,
    },
}

and then other variations before I finally realized this was a valid way to do it:

result := TerminateUserSessionResult{
    UserSession: UserSession{
        SessionID: session.SessionID,
    },
}

That said, https://docs.google.com/document/d/1zDgIzUCDE31AeAbhGUcdTQh-ISdFRcfrnaCdT8F2PDA is very clear about not using multi-part construction (which is what I was doing), so that should be kept in mind.