Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 3

Go Variables: Type Declaration and Inference

Recommended resources

Hello! Welcome back to your journey into Go.

In the last lesson, we focused on the fundamental Go workflow, using go run for quick development, go build to create distributable binaries, and go install to make your tools system-wide. You now have a solid foundation for turning code into executable programs.

Today, we'll shift our focus from the workflow to the code itself. This lesson covers how to declare and use variables using Go's static type system and type inference. This is the first step in managing data and state within your applications, a core skill for building any tool, from a simple configuration parser to a complex automation service.

Go's Static Typing: A Practical Perspective for DevOps

Coming from a background in Python and Bash, you're accustomed to dynamically typed languages. In Python, you can do this:

# In Python
config_value = 123      # config_value is an integer
config_value = "active" # Now it's a string, no problem

Go works differently. It is a statically typed language. This means that once a variable is declared to hold a certain type of data (like an integer), you cannot assign it a value of a different type (like a string). This isn't a limitation but a powerful feature for building robust systems. It allows the Go compiler to catch a whole category of bugs before you even run the program, preventing runtime errors that could crash your production automation scripts or services.

To see a direct comparison between Go and Python on this topic, the following article provides a concise explanation.

A Gentle Introduction to Go for Python Programmers

Read the first section of 'A Gentle Introduction to Go for Python Programmers' by Tolganay Zhuman. It directly contrasts Python's dynamic typing with Go's static approach and introduces the two main ways to declare variables.

Read the section titled '1. Basic Syntax and Variables'. Focus on the code examples for var name string = ... and age := 5.

This short video also provides a clear visual explanation of the difference between static and dynamic typing.

Static vs Dynamic Typing

Watch this brief segment from Boot.dev to solidify your understanding of static typing and see how Go enforces it.

Watch from 01:12 to 01:59. It shows a simple example of declaring an integer in Go and explains why its type cannot be changed later.


Declaring Variables in Go

Go gives you a few ways to declare variables, each suited for different situations. We'll explore them using a fantastic visual guide.

Go Variables - A Visual How-to Guide

The article 'Go Variables - A Visual How-to Guide' by Inanc Gumus provides clear, diagram-based explanations of variable declarations. We'll use it to walk through the main concepts.

Please read the sections titled 'Long Declaration', 'Short Declaration', and the advice under 'Which declaration form should I use?'. The diagrams are particularly helpful for visualizing the concepts.

Let's summarize the key points from the guide.

1. Long Form Declaration with var

The most explicit way to declare a variable is using the var keyword, followed by the variable name and then its type.

var hostname string
hostname = "localhost"

// You can also declare and initialize in one line
var port int = 8080

A crucial concept in Go is the zero value. If you declare a variable with var but don't assign it a value, Go automatically initializes it to a "zero value" corresponding to its type.

  • 0 for numeric types (like int, float64)
  • "" (an empty string) for string
  • false for bool

This prevents "uninitialized variable" errors that can occur in other languages. You use var when you need to declare a variable that will be assigned a value later or for variables declared outside of any function (at the package level).

2. Short Form Declaration with := (Type Inference)

Inside functions, you'll most often use the := operator. This is the short variable declaration operator, which tells Go to figure out the type automatically from the value you're assigning. This is called type inference.

// Inside a function (e.g., func main())
hostname := "localhost" // Go infers that hostname is a string
port := 8080            // Go infers that port is an int
isEnabled := true       // Go infers that isEnabled is a bool

This syntax is concise and readable, much like Python's assignment, but with one critical difference: the variable's type is now locked in.

Go Variable Declaration and Type Inference Example
This image shows both explicit declaration with `var age int` and short declaration with `:=`. Notice the compiler warns about the `age` variable being declared but not used—a strict rule in Go that keeps code clean.

The general rule of thumb is:

  • Use var when declaring variables at the package level (outside functions).
  • Use var inside a function if you need to declare a variable without initializing it immediately.
  • Use := in all other cases inside a function. It's the most idiomatic and common approach.

Go's Basic Data Types

Now that you know how to declare variables, let's look at the fundamental types you'll be working with. The video below gives a great overview, paying special attention to numeric types—something that is very important when considering performance and memory usage for your tools.

Learn GO Fast: Full Tutorial

This clip from the 'Learn GO Fast' tutorial details Go's basic data types. Pay close attention to the discussion on different integer and float sizes, as this is a key concept for optimizing your applications.

Watch from 06:40 to 11:19. This covers integers, floats, strings, and booleans.

Here's a summary of the basic types:

  • Strings (string): Used to store text. Go strings are UTF-8 encoded by default.
    configPath := "/etc/app/config.yaml"
    
  • Booleans (bool): Can be either true or false.
    enableTLS := true
    
  • Integers (int, int8, int16, int32, int64): For whole numbers.
    • int is the most common and its size (32 or 64 bit) depends on your system architecture.
    • Use specific sizes like int64 when you need to guarantee the size and range of the number, for example, when working with database IDs or timestamps.
    • There are also unsigned integer types (uint, uint8, etc.) which can only store non-negative values. An uint8 is often used to represent a byte.
  • Floating-point numbers (float32, float64): For decimal numbers.
    • float64 is the default and is generally what you should use unless you have a specific need to conserve memory.

Choosing the right numeric type is a practical consideration. For a tool parsing CPU metrics, float64 is appropriate. For a simple counter that won't exceed a few thousand, int is fine. For handling a large user ID from an API, int64 might be necessary to avoid overflow errors.


Hands-On Practice

Let's apply these concepts. Open your my-first-tool project and replace the contents of main.go with the following code. It declares a few variables that might be used in a typical DevOps script.

package main

import "fmt"

func main() {
	// Using short declaration for variables inside the function
	targetHost := "api.example.com"
	port := 443
	timeoutSeconds := 10.5 // Go infers this as float64
	isProduction := false

	// The 'var' keyword can be used to group declarations
	var (
		username string = "admin"
		password string // This will have a zero value: ""
	)

	fmt.Println("Connecting to:", targetHost)
	fmt.Println("Port:", port)
	fmt.Println("Timeout:", timeoutSeconds, "seconds")
	fmt.Println("Production Environment:", isProduction)
	fmt.Println("Username:", username)
	fmt.Println("Password set:", password != "") // Check if password is not its zero value
}
  1. Run the program using go run . to see the output.
  2. Experiment: Try to reassign a variable to a different type. For example, add the line port = "8080" after its declaration. What happens when you try to run the code? The compiler error you see is static typing in action.
  3. Modify: Change the value of isProduction to true and run it again.
Test your understanding!

Consider the following Go code snippet:

var apiVersion int
serviceName := "auth-service"
var isEnabled bool
  1. What is the value of apiVersion after it is declared?
  2. What is the data type of serviceName?
  3. If you later write isEnabled = "true", will the program compile? Why or why not?
Show answer
  1. The value of apiVersion is 0. This is the zero value for the int type.
  2. The data type of serviceName is string. The := operator causes Go to infer the type from the value "auth-service".
  3. No, the program will not compile. The variable isEnabled was declared as a bool, and Go's static type system prevents you from assigning a string value to it.

Conclusion

In this lesson, you've learned the fundamentals of how Go handles data through variables. This is a significant departure from dynamically typed languages like Python, but it brings immense benefits in reliability and error prevention.

Key Takeaways:

  • Static Typing: Go enforces that a variable's type is fixed at compile time, which helps you write safer, more robust code.
  • Variable Declaration: You can use the explicit var name type syntax or the more common, concise name := value shorthand inside functions.
  • Zero Values: Variables declared without an initial value are automatically set to a sensible default (0, "", false), eliminating a source of bugs.
  • Basic Types: You now know the essential building blocks for data: string, int, float64, and bool, and understand the importance of choosing sized numeric types for specific use cases.

Next Up

Now that you can store data in variables, the next step is to make decisions and perform repetitive tasks based on that data. In our next lesson, we will explore Go's control structures: if statements, for loops, and switch statements.