Utilizing Go Packages
Learn about packages, how to import them, and their usage in Go.
Go provides reusable blocks of code that can be imported into other code using packages. Packages in Go are synonymous with libraries or modules in other languages. Packages are the building blocks of Go programs that divide the content into understandable parts.
This lesson will cover how to declare and import a package. We’ll discuss how to deal with package name conflicts, explore rules around packages, and we’ll write our first main package.
Declaring a package
Go divides programs into packages, sometimes called modules or libraries in other languages. Packages live on a path, and the path is made to look like a path to a directory on a Unix-like filesystem.
All Go files in a directory must belong to the same package. The package is most commonly named the same as the directory it lives in. Declaring a package happens at the top of the file and should only be preceded by a comment. Declaring a package is as simple as the following:
// Package main is the entrance point for our binary.// The double slashes provides a comment until the end of the line./*This is a comment that lasts until the closing star slash.*/package main
The package main
is special. All other package names declare a package that must be imported into another package to be used. The package main
will declare func main()
, which is the starting point for a binary to run.
All Go files in a directory must have the same package header (compiler-enforced). These files, for most practical purposes, act as if they are concatenated together. Let's say we have a directory structure as follows:
mypackage/file1.gofile2.go
Then, file1.go
and file2.go
should have the following:
package mypackage
When mypackage
is imported by another package, it will include everything declared in all files in the mypackage
directory.
Importing a package
There are two general types of packages:
The standard library (
stdlib
) packagesAll other packages
Standard library packages stand out because they don't list some repository information in their path, such as the following:
"fmt""encoding/json""archive/zip"
All other packages generally have repository information preceding them, as follows:
"github.com/johnsiilver/golib/lru""github.com/kylelemons/godebug/pretty"
Note: A complete listing of
stdlib
packages can be found here.
To import packages, we use the import
keyword. So, let's import the standard library fmt
package and the mypackage
package, which lives at github.com/devopsforgo/mypackage
:
package mainimport ("fmt""github.com/devopsforgo/mypackage")
The filenames are not part of the package
path but simply the directory path.
Using a package
Once we've imported a package, we can start accessing functions, types, or variables declared in the package by prefacing what we want to access with the package's name and a period. For example, the fmt
package has a function called Println()
that can be used to print a line to stdout
. If we want to use it, it is as simple as the following:
func main(){fmt.Println("Hello!")}
Package name conflicts
Let's say we have two packages named mypackage
. They both have the same name, so our program won't be able to tell which one we are referring to. We can rename a package import into whatever name we want:
import("github.com/devopsforgo/mypackage"jpackage "github.com/johnsiilver/mypackage")
The jpackage
declares that in this package, we'll refer to github.com/johnsiilver/
mypackage
as jpackage
. This ability allows us to use two similarly named packages as follows:
mypackage.Print()jpackage.Send()
Now, we'll look at an important rule around packages that improve compile-time and binary size.
Packages must be used
Let's introduce the following rule: If we import a package, we must use it.
One of the things that the Go authors noticed about many of the other programming languages being used at Google was that they often had unused imports.
This led to compile times that were longer than needed and, in some cases, binary sizes that were much bigger than required. Python files were packaged in a proprietary format to ship around production, and some of these unused imports were adding hundreds of megabytes to the files.
To prevent these types of problems, Go will not compile a program that imports a package but doesn't use it, as shown below:
package mainimport ("fmt""sync")func main() {fmt.Println("Hello, playground")}
In certain rare circumstances, we may need to do a side effects import, in which just loading the package causes something to happen, but we don't use the package. This should always be done in package main
and requires prepending with an underscore (_
):
package mainimport ("fmt"_ "sync" //Just an example)func main() {fmt.Println("Hello, playground")}
Next, we will declare a main package and discuss the basics of writing a Go program that imports a package.
A Go hello world
Let's write a simple Hello World!
program. This example will demonstrate the following:
Declaring a package
Importing the
fmt
package from the standard library, which can print to our screenDeclaring the
main()
function of a programDeclaring a string variable using the
:=
operatorPrinting the variable to the screen
Let's see what this looks like:
package mainimport "fmt"func main() {hello:= "Hello World!"fmt.Println(hello)}
Let’s have a look at the highlighted lines shown in the code widget above:
Line 1: We declare the name of our package using the
package
keyword. The entrance point for any Go binary is a package namedmain
that has a function calledmain()
.Line 2: We import the
fmt
package.fmt
has functions for doing string formatting and writing to various outputs.Line 4: We declare a function called
main
that takes no arguments and returns no values. Themain()
is special, as when a binary is run, it starts by running themain()
function. Go uses{}
to show where a function starts and where a function ends (similar to C).Line 5: We declare a variable named
hello
using the:=
operator. The:=
operator indicates that we wish to create a new variable and assign it a value in a single line. This is the most common, but not the only, way to declare a variable.
Note: Since Go is typed,
:=
will assign the type based on the value. In this case, it will be a string, but if the value was an integer (such as 3), it would be theint
type, and if a floating-point (such as 2.4), it would be thefloat64
type. If we wanted to declare a specific type, such asint8
orfloat32
, we would need some modifications (which we'll talk about later).
Line 6: We call a function that is in the
fmt
package calledPrintln
. This function will print the contents of thehello
variable tostdout
followed by a new line character (\n
).
Note that the way to use a function declared in another package is to use the package name (without quotes) + a period + the function's name. In this case, fmt.Println()
.
In this lesson, we have learned how to declare a package, import a package, what the function of the main
package is, and how to write a basic Go program with a variable declaration.