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 secondint
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!