Golang Tutorials

Adding Functions To Structures

You can find Structure Basics and Structure Embedded have the previous Structure examples that we play off of in this how-to.

Here is a code example of a structure called "person" which contains a second structure "details". In addition to that, we have a new function of Create Person and we have extended the function of our person struct to contain a function called printPerson(bool)

package main

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

// Details 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 a functions and struct specific function to our new structure

// func keyword to declare function, followed by a methodname(), then the returntype
func createPerson() person {
	return person{
		ID: 1,
		details: details{
			firstName: "House",
			lastName:  "Cat",
			age:       34,
			address:   "Detroit Rock City",
		},
	}
}

// func keyword to declare function,
// followed by the receiver
// then function name and parameters
// finally, the return type (in this case nothing)
func (p person) printPerson(addDetails bool) {
	// The receiver adds function access to any variable of type person
	// p is a localized reference to the calling struct variable
	// p could be named anything you like
	// p is akin to programming conventions "this" and "self"
	// Works like extensions in C#

	if addDetails {
		fmt.Printf("%+v\n", p) // \n indicates a newline
	} else {
		fmt.Printf("%v\n", p)
	}
}

The comments really cover most of what is going on here. The receive declaration names a localized (pass by value) reference to this function. This is similar to this or self. We pass in a parameter to the function as well which we used to add some conditional logic on how to format print the calling variables values to console.


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

func main() {
	// Syntax ":=" is used to declare a variable and assign value in one step.
	// can only be used on local scoped variables
	person := createPerson()

	person.printPerson(false)
	person.printPerson(true)
}

As you can see, our code is starting to look organized and modular. That's exactly the point: grouping like functionality together. Single responsibility paradigms. Most, if not all, person logic should be grouped with the person structure.

A lot of online examples really have embraced the chaos. It seems some best practices are being out right ignored by junior and senior developers alike. Remember, those design practices may incur a tiny performance penalty but infinitely enhance readability. This has been proven time and time again. I feel it is self-evident but everytime a new language comes out, the first thing that excited trailblazers seem to do is ignore code hygeine or best practices. Always think SOLID or DRY when designing in any language, but specifically try to adhere to it in Golang and you will stand head and shoulders above other Go developers.

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
	details details
}

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

func main() {
	person := createPerson()

	person.printPerson(false)
	person.printPerson(true)
}

func createPerson() person {
	return person{
		ID: 1,
		details: details{
			firstName: "House",
			lastName:  "Cat",
			age:       34,
			address:   "Detroit Rock City",
		},
	}
}

func (p person) printPerson(addDetails bool) {
	if addDetails {
		fmt.Printf("%+v\n", p)
	} else {
		fmt.Printf("%v\n", p)
	}
}

Play.Golang.Org Sandbox

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