Go Variables, Types & Constants: Complete Guide

Go Variables, Types & Constants: Complete Guide
In our previous modules, we established the Go environment and wrote a basic "Hello World" application. Now, we dive into the core building blocks of any programming language: how to store and manage data.
Go is a statically typed language. This means the type of a variable is known at compile time, providing a massive layer of safety that dynamic languages like Python or JavaScript lack. However, Go's syntax is designed to be concise, giving you the safety of C++ with a feel closer to Python.
Go Variables and Types at a Glance
In Go, you declare variables with the var keyword or the shorthand := operator. The compiler infers the type from the assigned value, but the type is fixed at declaration — you cannot assign a string to an integer variable. Every declared variable is automatically initialized to its zero value, eliminating undefined behaviour and null-pointer bugs common in other languages.
The Philosophy of Explicit Typing
Declaring Variables
There are two primary ways to declare variables in Go. Both are used extensively, but they serve different purposes depending on the context.
1. The var Keyword
The var keyword is the formal way to declare a variable. It is most commonly used for package-level variables or when you want to declare a variable without immediately assigning it a value.
2. The Short Declaration Operator (:=)
For declaring and initializing variables inside functions, Go provides the short declaration operator. This is the most common way to create variables in Go.
| Task / Feature | var Keyword | Short Declaration (:=) |
|---|---|---|
| Scope | Inside or outside functions | ONLY inside functions |
| Initialization | Optional (defaults to zero value) | Required at declaration |
| Syntax | More verbose, explicit | Concise, uses type inference |
Fundamental Data Types
Go provides a robust set of built-in types. Because Go is designed for systems programming, it gives you granular control over memory by offering different sizes for integers and floats.
Go Basic Types
true, falseStandard boolean values for logic operations.
"Hello"UTF-8 encoded sequence of characters. Strings are immutable in Go.
42, -5Platform-dependent size (32 or 64 bit). Use int8, int32, int64 for specific sizes.
3.14159IEEE-754 floating-point numbers. float64 is the default for high precision.
The "Zero Value" Concept
In many languages, uninitialized variables contain "garbage" data or are null. In Go, every variable is initialized to a predictable Zero Value if no initial value is provided.
int: 0float: 0.0bool: falsestring: "" (empty string)pointers/interfaces: nil
Working with Constants
Constants are values that are known at compile time and cannot be changed during the execution of the program. They are declared using the const keyword.
Constants in Go are "untyped" until they are used in a context that requires a specific type, allowing for high flexibility without sacrificing safety.
Type Conversion
Go never automatically converts between types — you must be explicit. This prevents subtle bugs caused by implicit widening or narrowing in other languages.
Enumerated Constants with iota
The iota identifier generates a sequence of incrementing integer constants within a const block — it is Go's idiomatic way to define enumerations.
iota resets to zero at the start of each new const block, making it composable across multiple constant declarations.
Pointer Types
Go includes pointers, but unlike C, you cannot perform pointer arithmetic. Pointers are used to avoid copying large values and to allow functions to modify their arguments.
Pointers become central when you define methods on structs, which is explored in the Go functions, pointers, and structs guide.
Type Aliases and Defined Types
Go distinguishes between type aliases (type Celsius = float64) and defined types (type Celsius float64). A defined type creates a new, distinct type that does not implicitly convert with its underlying type — enforcing semantic clarity.
This strict type separation prevents you from accidentally mixing units, currencies, or any semantically different values that share the same underlying representation.
Blank Identifier
The blank identifier _ discards values you are required to receive but do not need — common with multi-return functions.
Use the blank identifier sparingly and always handle errors in production code. See the Effective Go section on the blank identifier for the full usage guidelines.
For the next step in your Go journey, the Go slices and maps guide builds directly on these type fundamentals to introduce Go's core collection types. For a comparison of how Go's type system differs from dynamic languages, visit the A Tour of Go — basic types section. The Go hello world and basics guide is the recommended starting point before this article if you are brand new to the language.
Next Steps
Understanding how to store data is the first major hurdle. However, programs aren't just static data; they need to make decisions and repeat tasks. In our next tutorial, we will explore Control Flow, including If/Else logic, Switch statements, and why Go only has one type of loop: the for loop.
Common Mistakes with Go Variables and Types
1. Shadowing variables with := inside blocks
Declaring x := 10 inside an if block creates a new variable that shadows the outer x. The outer variable is unchanged after the block exits. Use = (assignment) when you intend to modify an existing variable, and := only when declaring a new one.
2. Integer overflow without warning
Go does not panic on integer overflow — it wraps silently. If you are working with values that could exceed int32 or int64 bounds (e.g. financial calculations), use explicit bounds checks or the math/big package.
3. Comparing floating-point values with ==
0.1 + 0.2 == 0.3 evaluates to false in Go (and most languages) due to IEEE 754 floating-point representation. Use an epsilon comparison: math.Abs(a-b) < 1e-9. See the Go spec on numeric types for the full type hierarchy.
4. Using var when := is cleaner (and vice versa)
var is preferred at package level and when you need the zero value explicitly. := is idiomatic inside functions. Mixing them randomly reduces readability — pick the form that communicates intent.
5. Untyped constants surprising you at assignment
An untyped constant like const x = 1 takes on the type of whatever context it is used in. var y int8 = x works fine, but var y int8 = 200 overflows. Untyped constants have arbitrary precision until assigned.
Frequently Asked Questions
What is the zero value in Go?
Every variable in Go is automatically initialised to its zero value if not explicitly set: 0 for numeric types, false for booleans, "" for strings, and nil for pointers, slices, maps, channels, and interfaces. This eliminates a whole class of uninitialised-variable bugs. The Go spec on zero values documents this formally.
When should I use int vs int64?
Use int for general-purpose integer work — its size matches the platform (32-bit on 32-bit systems, 64-bit on 64-bit). Use int64 when you need a guaranteed 64-bit integer regardless of platform, such as when storing timestamps, file sizes, or working with external APIs that specify 64-bit integers.
Can I declare multiple variables on one line?
Yes. var a, b, c int = 1, 2, 3 and x, y := 10, 20 are both valid. The short form is idiomatic for return value unpacking: val, err := someFunc().
Continue Learning
Once you are comfortable with Go variables and types, the next step is Go Conditional Logic & Loops — covering if/else, switch, and the for loop (Go's only loop construct).
