Creating and Importing Go Packages

GoGoBeginner
Practice Now

Introduction

In the previous section, you completed your Go program, which included the following lines of code:

package main
import "fmt"

How do we understand these two lines of code? How do we use the package and import statements?

With these questions in mind, let's move on to this section's experiment.

In this lab, you will learn how to create and import packages in Go.

Knowledge Points:

  • Definition and declaration of a package
  • Different forms of importing packages

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL go(("`Go`")) -.-> go/BasicsGroup(["`Basics`"]) go(("`Go`")) -.-> go/FunctionsandControlFlowGroup(["`Functions and Control Flow`"]) go(("`Go`")) -.-> go/DataTypesandStructuresGroup(["`Data Types and Structures`"]) go/BasicsGroup -.-> go/variables("`Variables`") go/FunctionsandControlFlowGroup -.-> go/functions("`Functions`") go/FunctionsandControlFlowGroup -.-> go/closures("`Closures`") go/DataTypesandStructuresGroup -.-> go/pointers("`Pointers`") go/DataTypesandStructuresGroup -.-> go/strings("`Strings`") subgraph Lab Skills go/variables -.-> lab-149064{{"`Creating and Importing Go Packages`"}} go/functions -.-> lab-149064{{"`Creating and Importing Go Packages`"}} go/closures -.-> lab-149064{{"`Creating and Importing Go Packages`"}} go/pointers -.-> lab-149064{{"`Creating and Importing Go Packages`"}} go/strings -.-> lab-149064{{"`Creating and Importing Go Packages`"}} end

What is a Package?

Similar to Modules in Python or Libraries in C, a Package in Go is a collection of source code used for code reuse. Every Go code file needs to declare a package name, which is the package's definition. Each code file can also use code files belonging to the same package or import from other packages, which is package import.

Note: Every Go program must have one and only one package named main to mark the program's entry point. Otherwise, it will not generate an executable file after compilation.

Declaring and Defining Packages

Now that we understand the definition of a package in Go, can we create our own package?

Certainly! But keep in mind the following points:

  • In a Go package, type or function names starting with a lowercase letter are private, and those starting with an uppercase letter are public.
  • Code files in the same folder must have the same package.
  • The package name can be different from the folder name (although it is recommended to be the same). The package name should be in lowercase, without underscores or capital letters.
  • Just like Go variables, imported packages must be used, otherwise they will not compile.

Create a folder called propagandist and create a file with the same name, propagandist.go, in it.

mkdir ~/project/propagandist
touch ~/project/propagandist/propagandist.go

Write the following code in it:

package propagandist
var Shout = "I Love LabEx" // public variable
var secret = "I love the dress" // private variable
/*
   The distinction is made based on the first letter of the name:
   "Shout" starts with a capital letter
   "secret" starts with a lowercase letter
*/
func Hit() string {
    return "Don't hit me, please!"
}

We have now defined our own package.

To demonstrate later, let's initialize its go mod:

cd ~/project/propagandist
go mod init propagandist

You may be wondering whether the Hit() function in the package is a public or private method.

Single-Item Import

In the previous experiment, you learned how to import a package using the following syntax:

import "fmt"

This is the most common way to import packages in simple projects. Note that while the import keyword is the same as in Python, package names in Go must be enclosed in double quotation marks "".

Now let's create the exercise file pacExercise.go and initialize the go mod:

touch ~/project/pacExercise.go
go mod init pacExercise

Try to import the custom propagandist package and output I Love LabEx in pacExercise.

Multiple-Item Import

In the development process, most code requires multiple package imports. If we use single imports, it can become cumbersome, like this:

import "fmt"
import "bufio"
import "errors"
import "os"

To solve this problem, we can import multiple packages using a single import statement:

import (
    "fmt"
    "bufio"
    "errors"
    "os"
)

When using multiple imports, keep the following points in mind:

  • Use parentheses to maintain Go's coding style - Opening parentheses ( directly follows import, without line breaks.
  • Each package name must be enclosed in double quotation marks "".
  • Use line breaks to separate different packages, and do not add semicolons or other separators at the end.

Dot Import

If you add a dot . before the package name when importing a package like this:

import . "fmt"

You can omit the package name prefix when using the imported package.

What is the package name prefix omission? Let's modify pacExercise.go as follows:

package main

import . "fmt"

func main() {
    Println("Learning Package Management")
}

You will notice that we no longer need to add fmt. before Println when using the Println function.

Use go run pacExercise.go to run the code and observe that it produces the same output as before.

However, even with the dot import, can we still use the original writing method, such as fmt.Println("hello, world")?

Please try it out for yourself, as it will make a more lasting impression.

Alias Import

You can also choose a name of your liking for the imported package, as long as it does not conflict with any other package names. For example:

import io "fmt"

This renames the package fmt to io. Let's update pacExercise.go as follows:

package main

// import "fmt"
import io "fmt"

func main() {
    // fmt.Println("Learning Package Management")
    io.Println("Learning Package Management")
}

Run the program and observe that it still works as expected.

You can try renaming the fmt package as rw to achieve the same output.

Initialization Function of a Package

Before explaining anonymous import, let's introduce the initialization function of a package, init().

When a program is executed, the internal init function is automatically triggered. Note that init() is an optional function. For example, the helloWorld program we wrote earlier did not have an init function.

The points to note about the init function are as follows:

  • The init function has no parameters and does not return any values.
  • You cannot actively call it in your code.

Note: The usage of fmt.Print() is similar to fmt.Println(). It does not automatically break lines after output, as we will explain in later sections.

You can see that the initializer function init() runs before the main function in a program and after global declarations.

What about consecutive calls to multiple packages? Suppose our main package calls the fmt package, and the fmt package calls the io package, which in turn calls the error package.

Assuming each package has its own initialization function, what is the execution order?

In Go, the compiler starts from the main package and gradually checks subsequent packages, constructing a stack data structure.

During runtime, the initialization function is executed in the reverse order of the packages imported last, as shown in the following diagram:

Anonymous Import

For some package imports, we may only want to execute their initialization functions without using any methods in the package. In this case, we can use an anonymous import:

import _ "fmt"

This way, even if we import the package and don't use it, it won't result in a compilation error:

package main
import _ "fmt"
func main() {
    return
}

Try using an anonymous import in pacExercise.go to import the time package and not use any methods from it, while avoiding compilation errors.

Summary

In this lab, you learned how to create and import packages in Go. You also learned about the initialization function of a package and how to use anonymous imports.

Other Go Tutorials you may like