Learn about packages

Completed

Packages in Go are like libraries or modules in other programming languages. You can package your code and reuse it somewhere else. The source code of a package can be distributed in more than one .go file. So far, we've been writing the main package and have made a few references to other native packages.

In this section, you'll learn what a package is. You'll also learn how to create one and how to consume external packages.

Main package

As you might have noticed, even the most straightforward program in Go has to be part of a package. Usually, the default package is the main package, the one we've been using so far. If a program is part of the main package, Go generates a binary file. When that file runs, it calls the main() function.

In other words, when you use the main package, your program will produce a standalone executable. But when a program is part of a package other than main, Go doesn't generate a binary file. It generates a package archive file (a file that has the .a extension).

In Go, package names follow a convention. A package uses the last part of its import path as its name. For example, the Go standard library contains a package called math/cmplx, which provides useful code for working with complex numbers. The import path of this package is math/cmplx, and you import it like this:

import "math/cmplx"

To refer to objects in the package, you use the package name, cmplx, like this:

cmplx.Inf()

Let's create a package.

Create a package

Create a new directory in the $GOPATH/src directory called calculator. Create a file called sum.go. The tree directory should look like this directory:

src/
  calculator/
    sum.go

Initialize the sum.go file with the name of the package:

package calculator

You can now start to write the functions and variables for the package. Unlike other programming languages, Go doesn't provide the public or private keywords to indicate if a variable or function can be called from outside or inside of the package. But Go follows two simple rules:

  • If you want something to be private, start its name with a lowercase letter.
  • If you want something to be public, start its name with an uppercase letter.

So let's add the following code to the calculator package we're creating:

package calculator

var logMessage = "[LOG]"

// Version of the calculator
var Version = "1.0"

func internalSum(number int) int {
    return number - 1
}

// Sum two integer numbers
func Sum(number1, number2 int) int {
    return number1 + number2
}

Let's look at a few things in that code:

  • The logMessage variable can be called only from within the package.
  • The Version variable can be reached from anywhere. We recommend that you include a comment to describe the purpose of this variable. (This description is useful for anyone who uses the package.)
  • The internalSum function can be called only from within the package.
  • The Sum function can be reached from anywhere. We recommend that you include a comment to describe the purpose of the function.

To confirm that everything is working, you can run the go build command in the calculator directory. If you do, notice that no executable binary is generated.

Create a module

You've placed the calculator functionality inside a package. Now it's time to put that package into a module. Go modules typically contain packages that offer related functionality. A package's module also specifies the context that Go needs to run the code you've grouped together. This contextual information includes the Go version your code is written for.

Also, modules help other developers reference specific versions of your code and make working with dependencies easier. Another benefit is that our program's source code doesn't strictly need to exist in the $GOPATH/src directory. Freeing that restriction makes it more convenient to work with different package versions in other projects at the same time.

So, to create a module for the calculator package, run this command in the root directory ($GOPATH/src/calculator):

go mod init github.com/myuser/calculator

After you run this command, github.com/myuser/calculator becomes the module's name. You'll use that name to reference it in other programs. The command also creates a new file called go.mod. Finally, the tree directory now looks like this directory:

src/
  calculator/
    go.mod
    sum.go

The contents of the go.mod file should look like the following code. (The Go version might be different.)

module github.com/myuser/calculator

go 1.14

To reference your calculator package in other programs, you need to import it by using the module name. In this case, the name is github.com/myuser/calculator. Now let's look at an example of how to use this package.

Note

Historically, managing dependencies in Go hasn't been easy. The dependency management system is still a work in progress. If you want to learn more about modules, see this series of posts published in the Go blog.

Reference a local package (a module)

Now let's use the package. We'll continue with the sample application we've been using. This time, instead of having the sum function in the main package, let's use the one we created earlier in the calculator package.

The tree file structure now should look like this:

src/
  calculator/
    go.mod
    sum.go
  helloworld/
    main.go

We'll use this code for the $GOPATH/src/helloworld/main.go file:

package main

import (
  "fmt"
  "github.com/myuser/calculator"
)

func main() {
    total := calculator.Sum(3, 5)
    fmt.Println(total)
    fmt.Println("Version: ", calculator.Version)
}

Notice that the import statement uses the name of the package you created: calculator. To call the Sum function from that package, you need to include the package name, as in calculator.Sum. Finally, you now also have access to the Version variable. You call it like this: calculator.Version.

If you try to run the program now, it won't work. You need to tell Go that you're using modules to reference other packages. To do so, run this command in the $GOPATH/src/helloworld directory:

go mod init helloworld

In the previous command, helloworld is the name of the project. This command creates a new go.mod file, so now the tree directory looks like this:

src/
  calculator/
    go.mod
    sum.go
  helloworld/
    go.mod
    main.go

When you open the go.mod file, you should see something like the following code. (The Go version might be different.)

module helloworld

go 1.14

Because you're referencing a local copy of the module, you need to inform Go that you don't want to use a remote location. So you need to manually modify the go.mod file to include the reference, like this:

module helloworld

go 1.14

require github.com/myuser/calculator v0.0.0

replace github.com/myuser/calculator => ../calculator

The replace keyword specifies to use a local directory instead of a remote location for the module. In this case, because the helloworld and calculator programs are in $GOPATH/src, the location is simply ../calculator. If the module's source is in a different location, you define the local path here.

Run the program by using this command:

go run main.go

The output should be as follows:

8
Version:  1.0

Challenge 1

What happens if you try to call the logMessage variable or the internalSum function from the calculator package in the main application? Does it run? Give it a try!

Challenge solution:

package main

import (
 "fmt"
 "github.com/myuser/calculator"
)

func main() {
    total := calculator.internalSum(5)
    fmt.Println(total)
    fmt.Println("Version: ", calculator.logMessage)
}

Publish a package

Publishing a Go package is fairly easy. You just need to make the package source code publicly available. Most developers use GitHub to make packages available to the public, which is why you'll sometimes find references to github.com in import statements.

For example, if you want to publish your calculator package to your GitHub account, you need to create a repository named calculator. The URL should look similar to this one:

https://github.com/myuser/calculator

You'll version your packages by tagging your repository, like this:

git tag v0.1.0
git push origin v0.1.0

Developers who want to use your package (including you) would reference it like this:

import "github.com/myuser/calculator"

Let's talk in more detail about how to reference third-party packages.

Reference external (third-party) packages

Sometimes your programs need to reference packages written by other developers. Typically, those packages are available on GitHub. The following instructions for referencing third-party packages work whether you're developing a package (a package other than main) or a standalone program (the main package).

Let's add a reference to the rsc.io/quote package:

package main

import (
    "fmt"
    "github.com/myuser/calculator"
    "rsc.io/quote"
)

func main() {
    total := calculator.Sum(3, 5)
    fmt.Println(total)
    fmt.Println("Version: ", calculator.Version)
    fmt.Println(quote.Hello())
}

If you're using Visual Studio Code, the go.mod file is updated when you save the file. It now looks like this:

module helloworld

go 1.14

require (
    github.com/myuser/calculator v0.0.0
    rsc.io/quote v1.5.2
)

replace github.com/myuser/calculator => ../calculator

Notice how rsc.io/quote references a specific version of the package. When you need to upgrade your program's dependencies, you'll need to change the version here.

Run the program again by using this command:

go run main.go

The output should look like this:

8
Version:  1.0
Hello, world.

All future references to third-party packages will need to be in the go.mod file. When you run or compile the application, Go will download all of its dependencies.