Golang Tutorials

Structures In Structures

Head over to Structure Basics if you want to see the previous example.

Here is a code example of a structure called "person" which contains a second structure "details".

package main

// Person structure
type person struct {
	ID            int
	methodUsed    int
	personDetails details
}

// Person structure
/* type person struct {
	ID            int
	methodUsed    int
	details // alternatively you can just put in the structure info.
} */

// PersonDetails structure
type details struct {
	firstName string
	lastName  string
	age       int
	address   string
}

func main() {

}

In the commented out example, I demonstrate auto type-to-name declaration. The structure person with just the line details will now resolve to person.details as its member name and be of struct type details. While it's fully legal syntax, I do not encourage this usage style. Be as explicit as possible when declaring properties is the way to go to prevent ambiguity for the reader, but that is just humble opinion.


Next we are going to add some functions that use our new structure

// func keyword to declare function, followed by a methodname(), then the returntype
func createEmptyPerson() person {
	return person{}
}

// DeclarePerson1 returns a struct type of person, using the first method of instantiation.
func declarePerson1() person {
	return person{1, 1, details{"House", "Cat", 34, "Detroit Rock City"}}
}

// DeclarePerson2 returns a struct type of person, using the second method of instantiation.
func declarePerson2() person {
	return person{
		ID:         1,
		methodUsed: 2,
		personDetails: details{
			firstName: "House",
			lastName:  "Cat",
			age:       34,
			address:   "Detroit Rock City",
		},
	}
}

// DeclarePerson3 returns a struct type of person, using the third method of instantiation.
func declarePerson3() person {
	var newPerson person
	var personDetails details

	newPerson.ID = 1
	newPerson.methodUsed = 3

	personDetails.firstName = "House"
	personDetails.lastName = "Cat"
	personDetails.age = 34
	personDetails.address = "Detroit Rock City"

	newPerson.personDetails = personDetails
	return newPerson
}

Now we are going to call our methods from main() and check the outputs.

func main() {
	// := declare variable and assign value
	// can only be used on local scoped variables
	emptyPerson := createEmptyPerson()

	// print format with argument %v as value, so print emptyPerson
	fmt.Printf("Empty Person: %+v\n", emptyPerson)
	fmt.Printf("%+v\n", declarePerson1())
	fmt.Printf("%+v\n", declarePerson2())
	fmt.Printf("%+v\n", declarePerson3())
}

One interesting thing to note here is the useage of %+v. It prints out the values and the property names together.

Output

Empty Person: {ID:0 methodUsed:0 personDetails:{firstName: lastName: age:0 address:}}
{ID:1 methodUsed:1 personDetails:{firstName:House lastName:Cat age:34 address:Detroit Rock City}}
{ID:1 methodUsed:2 personDetails:{firstName:House lastName:Cat age:34 address:Detroit Rock City}}
{ID:1 methodUsed:3 personDetails:{firstName:House lastName:Cat age:34 address:Detroit Rock City}}

Additional Links


Everything Together

package main

import "fmt"

// Person structure
type person struct {
	ID            int
	methodUsed    int
	personDetails details
}

// PersonDetails structure
type details struct {
	firstName string
	lastName  string
	age       int
	address   string
}

func main() {
	emptyPerson := createEmptyPerson()

	// print format with argument %v as value, so print emptyPerson
	fmt.Printf("Empty Person: %+v\n", emptyPerson)
	fmt.Printf("%+v\n", declarePerson1())
	fmt.Printf("%+v\n", declarePerson2())
	fmt.Printf("%+v\n", declarePerson3())
}

// func keyword to declare function, followed by a methodname(), then the returntype
func createEmptyPerson() person {
	return person{}
}

// DeclarePerson1 returns a struct type of person, using the first method of instantiation.
func declarePerson1() person {
	return person{1, 1, details{"House", "Cat", 34, "Detroit Rock City"}}
}

// DeclarePerson2 returns a struct type of person, using the second method of instantiation.
func declarePerson2() person {
	return person{
		ID:         1,
		methodUsed: 2,
		personDetails: details{
			firstName: "House",
			lastName:  "Cat",
			age:       34,
            // below is an extra comma is needed when you do line by line assignment otherwise it won't compile
			address:   "Detroit Rock City", // <=
		}, // <= extra comma too which attaches to "details" being assigned
	}
}

// DeclarePerson3 returns a struct type of person, using the third method of instantiation.
func declarePerson3() person {
	var newPerson person
	var personDetails details

	newPerson.ID = 1
	newPerson.methodUsed = 3

	personDetails.firstName = "House"
	personDetails.lastName = "Cat"
	personDetails.age = 34
	personDetails.address = "Detroit Rock City"

	newPerson.personDetails = personDetails
	return newPerson
}

Play.Golang.Org Sandbox

I have embedded this source location for you to run and see outputs.