Published
- 5 min read
Variables, Constants, and Types in Go (The Right Way)

Understanding variables, constants, and types in Go isn’t just about syntax—it’s about embracing the philosophy behind Go’s minimalism and clarity. Go doesn’t overload you with features, but what it does give you, it expects you to use intentionally.
Variable Declarations in Go
Go offers flexible ways to declare variables, either using the concise short declaration := inside functions with automatic type inference, or the explicit var keyword for package-level variables or when you want to specify types or zero values. Understanding when and how to use each helps you write clear and idiomatic Go code.
Short Variable Declaration (:=)
It is used within functions, := lets the compiler infer the type from the right-hand side.
fruit := "Apple" // string
count := 3 // int
ratio := 3.14 // float64
- This works inside functions only and you cannot use := at the package level
- The compiler infers the type based on the assigned value using static analysis at compile time
- It’s very concise and idiomatic for local variables
Explicit Declaration with var
var city string = "Kathmandu"
var country = "Nepal"
var isActive bool
- Use var for package-level variables, or when you want to declare without immediate initialization
- You can omit the explicit type if you initialize immediately (
var country = "Nepal"
), and Go will infer the type automatically - When declared without initialization (
var isActive bool
), variables get their zero value (here:false
)
Declaration | Type inference? | Where valid? |
---|---|---|
fruit := “Apple” | Yes | Inside functions only |
var city string = “Kathmandu” | No (explicit) | Package-level and function scope |
var country = “Nepal” | Yes | Package-level and function scope |
var isActive bool | No (zero value) | Package-level and function scope |
Zero Values: Go’s Safety Net
If you declare a variable without initializing it, Go assigns a zero value depending on its type:
Type | Zero Value |
---|---|
int | 0 |
bool | false |
string | "" |
pointers, slices, maps, interfaces | nil |
Constants in Go
Use const for values that never change. Constants must be initialized with compile-time constant expressions
const Pi = 3.14
You can group constants:
const (
StatusOK = 200
StatusError = 500
)
Use iota for enumerations:
const (
Red = iota
Green
Blue
)
Here,
- iota is a predeclared identifier in Go.
- It’s used within constant declarations to generate successive untyped integer constants, starting from 0.
- It resets to 0 each time a new const block starts, and increments by 1 with each new line.
So in this example:
Constant Name | Value |
---|---|
Red | 0 |
Green | 1 |
Blue | 2 |
Types in Go
Go is statically typed, meaning every variable has a fixed type determined at compile time.
Basic types
Type | Size | Zero Value | Description | Use Case Example |
---|---|---|---|---|
bool | 1 byte | false | Boolean true/false value | Flags, conditional logic |
string | varies (UTF-8) | "" (empty) | Sequence of bytes interpreted as UTF-8 text | Text data, identifiers |
int | 32 or 64 bits (arch) | 0 | Signed integer, size depends on system architecture | Default integer type |
int8 | 8 bits | 0 | Signed 8-bit integer (-128 to 127 ) | Memory-efficient counters |
int16 | 16 bits | 0 | Signed 16-bit integer | Compact integer storage |
int32 | 32 bits | 0 | Signed 32-bit integer | Often used with rune |
int64 | 64 bits | 0 | Signed 64-bit integer | Large numbers, timestamps |
uint | 32 or 64 bits | 0 | Unsigned integer, depends on system architecture | Non-negative numbers |
uint8 | 8 bits | 0 | Unsigned 8-bit integer (0 to 255 ) | Alias: byte ; used for raw data |
uint16 | 16 bits | 0 | Unsigned 16-bit integer | Compact positive integers |
uint32 | 32 bits | 0 | Unsigned 32-bit integer | Bitflags, positive IDs |
uint64 | 64 bits | 0 | Unsigned 64-bit integer | High-precision counters |
byte | 8 bits (alias) | 0 | Alias for uint8 , represents a single raw byte | Binary I/O, buffers |
rune | 32 bits (alias) | 0 | Alias for int32 , represents a Unicode code point | Characters, text parsing |
float32 | 32 bits | 0.0 | 32-bit IEEE-754 floating point | Memory-efficient decimals |
float64 | 64 bits | 0.0 | 64-bit IEEE-754 floating point | Default for floating-point math |
complex64 | 64 bits | (0+0i) | Complex number with float32 real/imag parts | Signal processing, scientific math |
complex128 | 128 bits | (0+0i) | Complex number with float64 real/imag parts | High-precision complex calculations |
int
,uint
: Use when size isn’t critical; the size depends on whether you’re on a 32-bit or 64-bit architecture.byte
,rune
: Not separate types—just aliases with semantic meaning.complex64
andcomplex128
: Rarely used in typical application development, but supported natively for mathematical applications.
Custom Types
You can define your own types based on existing ones:
type Age int
var myAge Age = 29
This adds semantic meaning and improves type safety.
Type Conversion
Go does not allow implicit type conversion. You must convert explicitly:
var x int = 42
var y float64 = float64(x) // explicit conversion
Variable Scope and Lifetime
- Variables declared inside functions have local scope
- Variables declared at package level have global package scope and exist throughout the program lifetime
- Use var at package level; := is invalid there
package main
var globalVar = "I am global"
func main() {
localVar := "I am local"
fmt.Println(globalVar, localVar)
}
Common Mistakes
Shadowing with :=
x := 10
if true {
x := 20 // shadows outer x; this is a *new* variable
fmt.Println(x) // prints 20
}
fmt.Println(x) // prints 10
To modify an existing variable, use = instead of :=.
Using var unnecessarily inside functions
var fruit = "Apple" // verbose inside functions
fruit := "Apple" // preferred inside functions
Forgetting to use const for fixed values
var Pi = 3.14 // mutable, avoid this for constants
const Pi = 3.14 // immutable, preferred
Final Thoughts
Mastering how Go handles variables, constants, and basic types is more than just syntax—it’s about embracing Go’s design philosophy of simplicity, clarity, and correctness.
Here’s what to keep in mind:
- Use
:=
for concise, idiomatic variable declarations inside functions. - Use
var
when declaring at the package level or when you need zero-initialized values. - Use
const
for values that never change—it’s safer, clearer, and helps the compiler optimize. - Understand Go’s type system, including how zero values work and when to use explicit types.
- Use
iota
for clean, maintainable enumerations or bit flags.
By applying these practices early, you’ll write Go code that’s not just functional but idiomatic, predictable, and robust.