Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Go for DevOps

You're reading from   Go for DevOps Learn how to use the Go language to automate servers, the cloud, Kubernetes, GitHub, Packer, and Terraform

Arrow left icon
Product type Paperback
Published in Jul 2022
Publisher Packt
ISBN-13 9781801818896
Length 634 pages
Edition 1st Edition
Languages
Tools
Concepts
Arrow right icon
Authors (2):
Arrow left icon
John Doak John Doak
Author Profile Icon John Doak
John Doak
David Justice David Justice
Author Profile Icon David Justice
David Justice
Arrow right icon
View More author details
Toc

Table of Contents (22) Chapters Close

Preface 1. Section 1: Getting Up and Running with Go
2. Chapter 1: Go Language Basics FREE CHAPTER 3. Chapter 2: Go Language Essentials 4. Chapter 3: Setting Up Your Environment 5. Chapter 4: Filesystem Interactions 6. Chapter 5: Using Common Data Formats 7. Chapter 6: Interacting with Remote Data Sources 8. Chapter 7: Writing Command-Line Tooling 9. Chapter 8: Automating Command-Line Tasks 10. Section 2: Instrumenting, Observing, and Responding
11. Chapter 9: Observability with OpenTelemetry 12. Chapter 10: Automating Workflows with GitHub Actions 13. Chapter 11: Using ChatOps to Increase Efficiency 14. Section 3: Cloud ready Go
15. Chapter 12: Creating Immutable Infrastructure Using Packer 16. Chapter 13: Infrastructure as Code with Terraform 17. Chapter 14: Deploying and Building Applications in Kubernetes 18. Chapter 15: Programming the Cloud 19. Chapter 16: Designing for Chaos 20. Index 21. Other Books You May Enjoy

Utilizing Go packages

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 section will cover how to declare and import a package. We will discuss how to deal with package name conflicts, explore rules around packages, and we will 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

package main is special. All other package names declare a package that must be imported into another package to be used. 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 you have a directory structure as follows:

mypackage/
  file1.go
  file2.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) packages
  • All 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 at the following link: https://golang.org/pkg/.

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 main
import (
     "fmt"
     "github.com/devopsforgo/mypackage"
)

It is important to note that the filenames are not part of the package path, but simply the directory path.

Using a package

Once you've imported a package, you can start accessing functions, types, or variables declared in the package by prefacing what you want to access with the name of the package 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:

fmt.Println("Hello!")

Package name conflicts

Let's say you 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. You can rename a package import into whatever name you want:

import(
     "github.com/devopsforgo/mypackage"
     jpackage "github.com/johnsiilver/mypackage"
)

jpackage declares that in this package, we will 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 will look at an important rule around packages that improves compile-time and binary size.

Packages must be used

Let's introduce you to the following rule: If you import a package, you 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 was leading 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 here:

package main
import (
     "fmt"
     "sync"
)
func main() {
     fmt.Println("Hello, playground")
}

The preceding code outputs the following:

./prog.go:5:2: imported and not used: "sync"

In certain rare circumstances, you may need to do a side effects import, in which just loading the package causes something to happen, but you don't use the package. This should always be done in package main and requires prepending with an underscore (_):

package main
import (
     "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 that is similar to the default program in the Go Playground. This example will demonstrate the following:

  • Declaring a package
  • Importing the fmt package from the standard library, which can print to our screen
  • Declaring the main() function of a program
  • Declaring a string variable using the := operator
  • Printing the variable to the screen

Let's see what this looks like:

1 package main
2 
3 import "fmt"
4
5 func main() {
6    hello := "Hello World!"
7    fmt.Println(hello)
8
9 }

In our first line, we declared the name of our package using the package keyword. The entrance point for any Go binary is a package named main that has a function called main().

In our third line, we import the fmt package. fmt has functions for doing string formatting and writing to various outputs.

On our fifth line, we declare a function called main that takes no arguments and returns no values. main() is special, as when a binary is run, it starts by running the main() function.

Go uses {} to show where a function starts and where a function ends (similar to C).

The sixth line declares a variable named hello using the := operator. This 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.

As Go is typed, so := 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 the int type, and if a floating-point (such as 2.4), it would be the float64 type. If we wanted to declare a specific type, such as int8 or float32, we would need some modifications (which we will talk about later).

On the seventh line, we call a function that is in the fmt package called Println. Println() will print the contents of the hello variable to stdout followed by a new line character (\n).

You will notice that the way to use a function declared in another package is to use the package name (without quotes) + a period + the name of the function. In this case, fmt.Println().

In this section, you 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. In the next section, we will go into some depth on declaring and using variables.

You have been reading a chapter from
Go for DevOps
Published in: Jul 2022
Publisher: Packt
ISBN-13: 9781801818896
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime