If you want to upgrade your skills and minimize the portion of boring stuff like leveling your code up to the standards of the Go community, you should master Go tool chain. It helps you apply the best practices for writing Go code. They are needed to achieve the readability of the code, compliance with the styles of Go, and effectiveness in defining possible issues in the code.
In this topic, we will focus on some tools such as go vet, gofmt, golint, and goimports.
Go vet
To clearly illustrate how these tools help us, let's create a simple BMI calculator project. We ask for two user inputs: height and mass, and calculate the BMI using the following formula:
Then, the program displays to which category they belong. Note that this is a fully functional mini-project; however, there are a couple of problems, and using some specific Go tools we will fix them step-by-step.
package main
import "fmt"
func main() {
fmt.Println("Enter Your Height in m: ")
var person_height float32
fmt.Scanln(&person_height)
fmt.Println("Enter Your Mass in kg: ")
var person_mass float32
fmt.Scanln(&person_mass)
BMI := person_mass / (person_height * person_height)
if BMI < 18.5 {
fmt.Printf("You're underweight, because your BMI is %.2s", BMI)
} else if BMI < 24.9 {
fmt.Printf("You're healthy weight, because your BMI is %.2s", BMI)
} else if BMI < 29.9 {
fmt.Printf("You're overweight, because your BMI is %.2s", BMI)
} else {
fmt.Printf("You have obesity, because your BMI is %.2s", BMI)
}
}Let's start with go vet. go vet analyzes our code for possible issues that were not caught by the Go compiler. It is a good tool for finding logical errors. To be specific, it is handy when you need to check if the code aligns with the formatting of Printf. Moreover, go vet can be used to check for unused assignments and possible mistakes in boolean operations. However, it is crucial to keep in mind that go vet is a guide, not an indicator of the correctness of a program. To demonstrate it let's run the BMI code with the inputs 1.84 for the height and 80 for the mass. As a result, we obtain the following output
You're healthy weight, because your BMI is %!s(float32=24)We see that our code works, but does not display the BMI value correctly. We can check those kinds of possible mistakes using go vet. Go vet does not require installation as it is installed as a part of standard Go. To run go vet, type in the terminal the following lines go vet projectName.go in the directory where the project file is located. The output will be
# command-line-arguments
.\BMIProject.go:19:3: fmt.Printf format %.2s has arg BMI of wrong type float32
.\BMIProject.go:21:3: fmt.Printf format %.2s has arg BMI of wrong type float32
.\BMIProject.go:23:3: fmt.Printf format %.2s has arg BMI of wrong type float32
.\BMIProject.go:25:3: fmt.Printf format %.2s has arg BMI of wrong type float32This warning says that you are trying to pass the value of the float type into the place where the string is expected. If s in %.2sis changed tof then you get the correct output
You're healthy weight, because your BMI is 23.63Style check with golint
If go vet is used to look for possible bugs, golint is another tool for styling the Go code according to conventions mentioned in Effective Go in the official documentation of the language. golint is a linter for Go developers. Note that it is one of the many linters available for Go developers and its suggestions are not a gold standard. To run the golint, you should install it first. Type the following code in the terminal and wait for the installation
go install golang.org/x/lint/golint@latestThen type golint projectName.go. If you check the BMI project for stylistic suggestions, you obtain the following styling advice:
BMIproject.go:8:6: don't use underscores in Go names; var person_height should be personHeight
BMIproject.go:13:6: don't use underscores in Go names; var person_mass should be personMassAs you see, linter says to use the appropriate naming style. Technically there is no mistake, but in Golang camel case is used to name the variables, not the snake case. Let's apply it and rerun the above linter check. Your code should look like this.
package main
import "fmt"
func main() {
fmt.Println("Enter Your Height in m: ")
var personHeight float32
fmt.Scanln(&personHeight)
fmt.Println("Enter Your Mass in kg: ")
var personMass float32
fmt.Scanln(&personMass)
BMI := personMass / (personHeight * personHeight)
if BMI < 18.5 {
fmt.Printf("You're underweight, because your BMI is %.2f", BMI)
} else if BMI < 24.9 {
fmt.Printf("You're healthy weight, because your BMI is %.2f", BMI)
} else if BMI < 29.9 {
fmt.Printf("You're overweight, because your BMI is %.2f", BMI)
} else {
fmt.Printf("You have obesity, because your BMI is %.2f", BMI)
}
}If we rerun golint, we obtain no output. It means our code follows all stylistic suggestions.
Formatting with gofmt and goimports
You have already seen tools for bug check and style check, and let's add to our arsenal tools that help us format our code. As in the case of golint, there are plenty of formatting tools, but the most popular of them are gofmt and goimports. They improve the readability of the code without affecting the execution.
The usage of these tools is pretty straightforward. gofmt as go vet comes with standard Go installation; therefore, there is no need for extra action. You might already have noticed how we call these tools in the terminal; we write the tool's name and the project's name. Let's use gofmt first on our previous code. Type gofmt projectName.go into the terminal and see what it returns.
The output is:
package main
import "fmt"
func main() {
fmt.Println("Enter Your Height in m: ")
var personHeight float32
fmt.Scanln(&personHeight)
fmt.Println("Enter Your Mass in kg: ")
var personMass float32
fmt.Scanln(&personMass)
BMI := personMass / (personHeight * personHeight)
if BMI < 18.5 {
fmt.Printf("You're underweight, because your BMI is %.2f", BMI)
} else if BMI < 24.9 {
fmt.Printf("You're healthy weight, because your BMI is %.2f", BMI)
} else if BMI < 29.9 {
fmt.Printf("You're overweight, because your BMI is %.2f", BMI)
} else {
fmt.Printf("You have obesity, because your BMI is %.2f", BMI)
}
}It seems like we missed some spaces at the beginning between the lines. And the tool has added it for us. After typing gofmt in the terminal you also can type the package name instead of the file name. As you might notice, the fixed code was returned in the standard output. There can be cases when you do not need to return fixed code. Instead, you might be interested in the list of files to which formatting changes are required. In such a scenario, some flags before the file or package name can be added during the gofmt call.
-lflag prevents fixed code to be printed in the standard output. Instead, it returns the list of files that differs fromgofmtformatting. To apply it, use the following in the terminalgofmt -l package or file name-wflag prevents fixed code to be printed in the standard output. Instead, formatting styles are applied to the source file. To apply it, use the following in the terminalgofmt -w package or file name-dflag does not print the fixed and changed code in the standard output. Instead, it prints the difference between the reformated and the original code by indicating the lines with-and+signs. The plus sign indicates the line is changed. To apply it, use the following in the terminalgofmt -d package or file name
goimports does the same formatting with one exception. It adds missed imports and removes unreferenced ones. For example, when we write code, there can be cases when we have unreferenced packages or miss some packages that we forgot to import.
In such cases, goimports removes unreferenced packages, adds the missing ones for us, and sorts them by grouping them into third-party and standard library ones. By third-party, it means packages taken from GitHub repositories. Unfortunately, goimports does not come with a standard installation, therefore to install it, the following line should be typed into the terminal:
go install golang.org/x/tools/cmd/goimports@latestTo run the tool, the command type is goimports projectName.go, and it will return the formatted code in the terminal as gofmt did before.
Conclusion
In the Go environment, there are a lot of extra tools that can be used for different goals in order to increase the efficiency of the code. The code should not only execute, but it also should follow language standards and should be readable. Use the following tools to make your code beautiful
go vetfor possible problems check that was not captured by the compilergolintfor a style checkgofmtandgoimportsfor format check