Go Beginners Series: Function Declarations, Parameters, Return Values, and Packages

Go Beginners Series: Function Declarations, Parameters, Return Values, and Packages

Functions are the backbone of every application you will ever write as a programmer. Without functions, your application will be a long file of code that is difficult to manage, understand and reuse. Packages, on the other hand, are different files and folders that programmers use to define code that they intend to share with other files. This helps you to organize, compartmentalize and reuse your code, thus reducing code repetition and increasing maintainability.

In the previous article, you learned about control flow and how to manipulate it using if-else, else if, and switch statements in Go. In this article, you will learn how to use functions and packages to make your Go applications easy to understand, manage, debug, and reuse.

Functions in Go

Like every other programming language, Go allows you to define functions you can reuse in different parts of your application just by calling them.

For example, if you are building a blog application that allows users to like posts, you would need to add 1 to the post's likes in the database and update it on the blog. Also, the like button should show on the post whether it is on the Homepage or the Recommendations under another post; functions allow you to define a block of code that would add the like to the database and use it in multiple places throughout your application.

A function in Go is defined using the func keyword, followed by the name of the function, a list of parameters inside parentheses ( ), followed by the curly braces { } that will contain the code statements you want to execute when the function is called. Add the following code inside the main.go file:

var postLikes int = 0

func addLike(postID int) {
 //find the post in the database
 postLikes++
 fmt.Println("The post with ID:", postID, "now has", postLikes, "likes.")
}

The code above declares a postLikes variable with the value of 0 and a function called addLike that takes in an ID of the post that needs to be updated, finds the post in the database, updates it, and prints a message to the user.

The code above will not do anything but can now be used anywhere in the file. To use the function, add the following code inside the main function:

 addLike(10)

The code above will call the addLike function and return the following:

The post with ID: 10 now has 1 likes.

Let's explore function parameters next.

Function Parameters in Go

Go allows you to define the data values your functions need to work correctly. An example of this is the postID int inside the previous function's parentheses. You can add multiple parameters to your functions; for example, if you want to check if a user has already liked a post before adding another like to the database, you can do that like so:

func addLike(postID int, userID int) {
 //find the post in the database
 //check if the user has liked the post
 postLikes++
 fmt.Println("The post with ID:", postID, "now has", postLikes, "likes")
}

The code above is the same as the previous one, but this one has an additional parameter, userID which is used to check if a user has already liked a post before proceeding with the function.

Note: You can add zero to any number of parameters to your functions. Also, if the parameters on the right are of the same type as in the addLike function above, you can omit the second int like so: addLike(postID, userID int), and the code should still work fine.

Return Values in Go

Like most programming languages, Go allows developers to return a value at the end of a function using the return keyword. For example, if you want to return the number of likes that a post now has to the user, you can do that like so:

func addLike(postID int, userID int) int {
 //find the post in the database
 //check if the user has liked the post
 postLikes++
 fmt.Println("The post with ID:", postID, "now has", postLikes, "likes")
 return postLikes
}

The code above is the same as the previous one, but this one has a return value that returns the new number of likes to the user. Also, notice the int after the parameter parentheses, which is the type of value that the function is returning.

Multiple Return Values in Go

You can return more than one value inside your Go functions. For example, to return the postLikes and ID of the last person that liked the post, you can update the addLike function like so:

func addLike(postID int, userID int) (int, int){
 //find the post in the database
 //check if the user has liked the post
 postLikes++
 fmt.Println("The post with ID:", postID, "now has", postLikes, "likes")
 return postLikes, userID
}

The code above is the same as the previous one, but this one has two return value that returns the new number of likes and the last ID of the last person that liked the post to the user. Also, notice the (int, int) after the parameter parenthesis, you need to add the type of each return value inside a parenthesis if there is more than one.

Now that you know how to define functions, use parameters and arguments, and return single and multiple values in Go, let's explore the packages and how to use them in the next section.

Packages in Go

So far in this series, you have only written code inside the main.go file, and while this is okay for the type of code we've been writing, it is not scalable and can quickly get messy and complicated to manage when you start writing big applications.

Like other major programming languages, Go allows you to share and reuse code across files and folders in your application using packages. For example, if you are building a blog application, you might want to have different folders for user authentication, database operations, admin authentication, etc.

To create and use a custom package in Go, you need to generate a go.mod file in your application folder. Run the following command:

go mod init yourappname

The command above will create a go.mod file inside your application folder with the following contents:

module yourappname

go 1.20

Note: If you have a different version of Go installed on your machine, that version will be written instead of 1.20.

Next, run the following command to create these folders in your application folder:

mkdir dbOps userAuth adminAuth

The command above will create three folders; dbOps, userAuth, and adminAuth in your application folder. Next, create a file with the same name as the folder inside the respective folders, and your folder structure should now look like so:

├── yourappname
│   └── adminAuth
│       └── adminAuth.go
│   └── dbOps
│       └── dbOps.go
│   └── userAuth
│       └── userAuth.go
│   ├── go.mod
│   ├── main.go

Add the following code to the userAuth/userAuth.go file:

package userauth

import (
 "fmt"
)

var name, surname string = "Adams", "Adebayo"

func Login() {
 fmt.Print("Welcome to the login page", name, " ", surname, " ", "Please enter your username and password to login. ")
}

func Logout() {
 fmt.Print("User:", name, " ", surname, " ", "successfully logged out. Thanks for using our service. ")
}

func SignUp() {
 fmt.Print(`Welcome to the admin signup page. Please enter your details to sign up. `)
}

The code above defines the file as part of the userauth package, imports the fmt package, defines two variables, name and surname, and three functions; Login, Logout, and SignUp.

Note: Functions and variables that you intend to use in other files, also known as Exported Variables and Functions must start with a capital letter, while the ones that begin with lowercase letters will only be available for use in the same file.

And that's it! You can now share code between the files in your Go application. Let's explore how to do that in the next section.

Sharing Code Between Files in Go

In the previous section, you set up three folders to hold different functionalities of your application; in this section, you will write and share code between these folders.

To use the exported functions inside the userAuth/userAuth.go file in the main.go file, you need to import them. Replace all the code inside the main.go file with the following:

package main

import (
 "fmt"
 "yourappname/userauth"
)

func main() {
 userauth.Login()
 fmt.Println()
 userauth.Logout()
 fmt.Println()
 userauth.SignUp()
 fmt.Println()
}

The code above defines the file as part of the main package, imports the fmt and yourappname/userauth packages, defines the main function, and calls the three exported functions from the userAuth file; Login, Logout, and SignUp with a line break between them. Run the app with the run command:

go run .

The code should return the following statements:

Welcome to the login page Adams Adebayo Please enter your username and password to login.
User: Adams Adebayo successfully logged out. Thanks for using our service.
Welcome to the admin signup page. Please enter your details to sign up.

Now that you know how to create and use functions, let's explore the init function in the next section.

The init Function

Go allows you to define an init function that will be called every time the package is initialized. This function will only be called once and cannot have any parameters. Add the following code to the userAuth/userAuth.go file:

func init() {
 fmt.Println("The userAuth file has been initialised")
}

The code above will run immediately after you run your application, and you do not need to export it explicitly.

Import Aliases in Go

Go allows you to specify an alternate name for your imported packages with import aliases. For example, userauth might be a little too long to type every time you need to use the package; you can use an import alias to shorten the name like so:

import (
 "fmt"
 ua "yourappname/userauth"
)

The code above imported the userauth package with the alias ua. You can now use the package in the main function like so:

func main() {
 ua.Login()
 fmt.Println()
 ua.Logout()
 fmt.Println()
 ua.SignUp()
 fmt.Println()
}

The code should work the same way as the previous section. This approach is handy for packages with longer names; however, this can make your code less readable if overused.

The Blank (_) Identifier

If you want to import a package into a file without using it, you can do so without getting an error by using the _ symbol like so:

import (
 "fmt"
 _ "yourappname/userauth"
)

You can now import the package without using it in the file. However, if you try to use it after importing it this way, your application will throw an error.

Conclusion

Organizing your code properly is something you should take very seriously as a developer because it will save you a lot of time and stress; unorganized and messy code might feel fast at the moment but can quickly turn into something that feels impossible to understand as your application get bigger.

I hope this article achieved its aim of teaching everything you need to know about functions and packages in Go. We will explore the different data structures in Go and how to use them.

Please leave your feedback, corrections, questions, and suggestions in the comment section, and I'll reply to all of them. Thanks again!