Variables and Data Types
Go's type system is statically typed with type inference via the short declaration operator :=.
Introduction
Go's type system is statically typed with type inference via the short declaration operator :=. Understanding basic types, zero values, and when to use explicit types versus inference is foundational for every backend service you will build.
Unlike C#, Go has no implicit numeric conversions — you must cast explicitly. Strings are immutable UTF-8 byte sequences. Understanding zero values (0, "", false, nil) prevents subtle bugs when variables are declared but not initialized.
This lesson covers int, float64, bool, string, byte, rune, and the rules for variable shadowing in inner scopes — topics that appear frequently in Go coding interviews and code review discussions.
The story
A ride-sharing billing microservice (similar to Uber's ledger pipeline) stores each trip snapshot with a UUID, fare in cents as an integer, and a timestamp. Using int64 for money in the smallest currency unit avoids floating-point rounding bugs that have caused real payment discrepancies in production.
When a rider receives a $12.50 credit, the service creates a new snapshot rather than mutating history — preserving the audit trail regulators expect from financial software deployed on GCP.
Understanding the topic
Key concepts
- Basic types: bool, string, int, int8/16/32/64, uint, float32/64, complex64/128, byte (alias uint8), rune (alias int32).
- var name type declares with zero value; name := value infers type (short declaration).
- Zero values: 0 for numbers, false for bool, "" for string, nil for pointers/slices/maps/channels.
- Type conversion: T(v) syntax — no implicit widening or narrowing.
- const declares compile-time constants; iota creates enumerated constants.
- Shadowing: inner := redeclares in inner scope — can hide outer variables.
classDiagramclass ValueTypes {intfloat64boolstruct}class ReferenceTypes {stringslicemappointer}
Step-by-step explanation
- Declare with var or := inside functions; := only works inside functions.
- Go infers type from literal: x := 42 is int, y := 3.14 is float64.
- Explicit conversion required: float64(i) * 1.5.
- Multiple declaration: a, b := 1, "hello".
- Blank identifier _ discards unwanted return values.
- Compiler rejects unused variables at package and function scope.
Practical code example
Demonstrating types, inference, conversion, and zero values in a payment calculation:
package mainimport "fmt"func main() {// Explicit typevar balance float64 = 1000.50transactionCount := 3 // inferred int// Type conversion requiredfeeRate := 0.025fee := balance * feeRatetotal := balance + fee// Multiple assignmentaccountID, currency := "ACC-001", "USD"// Zero value demovar pending bool // falsefmt.Printf("Account %s (%s): balance=%.2f fee=%.2f total=%.2f txns=%d pending=%v\n",accountID, currency, balance, fee, total, transactionCount, pending)}
Line-by-line code explanation
var tripID stringdeclares a variable with the zero value (empty string).tripID := uuid.New().String()uses short declaration with inference — the most common style.const CurrencyUSD = "USD"defines a compile-time constant that cannot change.fareCents int64 = 1250stores $12.50 as 1250 cents — never usefloat64for money.time.Now().UTC()records when the snapshot was taken in UTC for API consistency.fmt.Sprintf("%s-%d", tripID, fareCents)builds a log line without separate concatenation.var count intzero-initializes to 0 — Go never leaves variables uninitialized.count++increments the accumulator in a loop processing trip batches.
Key takeaway: Use float64 for general math; use shopspring/decimal or int64 cents for financial precision in production. Unused variables cause compile errors — Go enforces clean code.
Real-world use
Where you'll use this in production
- Parsing and validating API request fields with explicit types.
- Configuration values loaded from env vars into typed structs.
- Metrics counters and gauges in observability agents.
- Protocol buffer and JSON field mapping with strict types.
Best practices
- Prefer := for local variables when type is obvious from the right side.
- Use int for loops and indices; int64 for IDs and timestamps (Unix epoch).
- Store money as int64 cents or use decimal library — avoid float64 for currency.
- Name variables descriptively; single-letter only in short loops (i, j, k).
- Avoid shadowing — use different names or smaller scopes deliberately.
- Use strconv for string↔number conversion with error checking.
Common mistakes
- Implicit conversion like Java — Go requires explicit T(v) casts.
- Using float64 for money — rounding errors in financial systems.
- Declaring variables with var and never assigning — zero value surprises.
- Shadowing err in nested scopes — classic bug in error handling.
- Using int when uint is needed for bit operations without understanding signedness.
Advanced interview questions
Q1BeginnerValue type vs reference type in Go?
Q2BeginnerWhat is a zero value?
Q3IntermediateDifference between var and :=?
Q4IntermediateWhy no implicit numeric conversion?
Q5AdvancedExplain variable shadowing and why it matters with err.
Summary
Go is statically typed with inference via := and explicit var declarations. Zero values apply automatically; no uninitialized variable undefined behavior. Type conversions are explicit — no implicit widening. Use appropriate types for domain: int64 for IDs, decimal for money. Next lesson: constants, operators, and iota enumerations.