DEV Community

Cover image for The Secret Life of Go: Variables & Types
Aaron Rose
Aaron Rose

Posted on

The Secret Life of Go: Variables & Types

Chapter 2: Variables, Types, and the Art of Declaration

The morning light streaming through the tall windows of the Whitmore Archive had a different quality today—sharper, more purposeful. Ethan arrived precisely at ten, as Eleanor had suggested, carrying two cups of coffee in a cardboard tray. The aroma of single-origin Ethiopian beans preceded him down the stairs.

Eleanor looked up from her desk, one eyebrow raised in approval. "Bluestone Lane?"

"They remembered you from yesterday," Ethan said, setting her cup down carefully. "The barista said 'the usual for the elegant woman who knows her coffee.'"

"I may have been going there since 1994." Eleanor lifted the cup and inhaled. "Perfect. Now sit. Today we learn about identity."

Ethan pulled out the spare laptop. "Identity?"

"In Go, everything has a name and a type. The language insists on it." She opened a new file. "Tell me, what's your age?"

"Twenty-three."

"And what kind of thing is twenty-three?"

"A... number?"

"An integer, specifically. A whole number." Eleanor's fingers moved across the keyboard. "Watch. Today we're going to write a program that introduces you properly. Here's what we want it to do:"

She turned the screen toward him:

Hello! My name is Ethan.
I am 23 years old.
Next year I'll be 24 .
Enter fullscreen mode Exit fullscreen mode

"Simple output," Eleanor said. "But to get there, we need to teach Go who you are. Let's look at the code that produces this:"

package main

import "fmt"

func main() {
    var name string = "Ethan"
    var age int = 23

    fmt.Println("Hello! My name is " + name + ".")
    fmt.Println("I am", age, "years old.")

    age = age + 1
    fmt.Println("Next year I'll be", age, ".")
}
Enter fullscreen mode Exit fullscreen mode

Ethan studied the screen. "That's more than we wrote yesterday."

"Yesterday we learned about packages and imports. Today we learn about variables—the things that hold information." She pointed to the first line inside main. "Look at this declaration: var name string = "Ethan". What do you see?"

"The word var, then name, then string, then equals and my name in quotes."

"Exactly. Let's break it down." Eleanor opened her notebook and wrote:

var     - keyword that says "I'm declaring a variable"
name    - the name we're giving this variable
string  - the type of data it will hold
=       - assignment
"Ethan" - the initial value
Enter fullscreen mode Exit fullscreen mode

"Go requires you to declare what type of data a variable will hold. A string holds text. An int holds integers. No surprises, no guessing." She tapped the second line. "And here we declare age as an int holding the value 23."

"In Python," Ethan said slowly, "I could just write name = "Ethan" and it would figure out it's a string."

"Python infers the type," Eleanor agreed. "Go can do that too, actually. But first, let's understand what Go is doing explicitly. Once you see the machinery, we can talk about shortcuts."

She scrolled down. "Notice something about the print statements. On line 8, I used "Hello! My name is " + name + "." with the + operator. That's string concatenation—joining text together. But on line 9, I used commas: "I am", age, "years old." Why the difference?"

Ethan looked closer. "The second one mixes a number and text?"

"Exactly. In Go, you can use + to join strings together. But you cannot use + to join a string and an integer—Go's type system won't allow it. So when we need to print mixed types, we use commas. Println automatically adds spaces between comma-separated values and handles the conversion for us."

"So that's the type safety you mentioned?"

"Precisely. If I had tried to write age + "." on line 12, Go would refuse to compile. It would say 'you're trying to add an integer and a string—that doesn't make sense.' The language protects you from mixing types accidentally."

She pointed to line 11. "Now look at this line: age = age + 1. We're taking the current value of age, adding one, and storing it back into age. The variable changes. That's what makes it a variable rather than a constant."

"So constants don't change?"

"Correct. We'll get to those later. For now, understand that variables are containers that can hold different values over time." Eleanor turned the laptop toward him. "Let's look at the structure of what we just wrote. This will help you see how Go organizes code."

📦 Package: main
    📥 Import: "fmt"
    🔧 Function: main()
        📝 Variable: name (string) = "Ethan"
        📝 Variable: age (int) = 23
        📞 Call: fmt.Println("Hello! My name is " + name + ".")
        📞 Call: fmt.Println("I am", age, "years old.")
        📝 Assignment: age = age + 1
        📞 Call: fmt.Println("Next year I'll be", age, ".")
Enter fullscreen mode Exit fullscreen mode

"See how everything has its place?" Eleanor traced the outline with her finger. "The package at the top, the import just below, then our function containing our variables and operations. Go insists on this hierarchy—it's not negotiable, and that's actually freeing. You never wonder where something should go."

Ethan nodded. "It's like... everything is labeled."

"Precisely. Now let's break this down into plain English, so you can see what each piece actually does:"

Package Declaration: This file is part of the 'main' package (executable program)

Import Statement: We need the 'fmt' package for printing to the screen

Function Declaration: Define a function named 'main' (the starting point)

    Variable Declaration: Create a variable named 'name'
        - Type: string (text)
        - Initial value: "Ethan"

    Variable Declaration: Create a variable named 'age'
        - Type: int (whole number)
        - Initial value: 23

    Print Statement: Display "Hello! My name is " + name + "."
        - Uses string concatenation (+) to join text pieces
        - Result: "Hello! My name is Ethan."

    Print Statement: Display "I am", age, "years old."
        - Uses comma-separation to mix int and string
        - Println automatically adds spaces between comma-separated values

    Assignment: Calculate age + 1 and store the result back in 'age'
        - Before: age = 23
        - After: age = 24

    Print Statement: Display "Next year I'll be", age, "."
        - Uses comma-separation (can't use + to join int and string)
        - Go's type safety: numbers and strings don't mix with +
Enter fullscreen mode Exit fullscreen mode

"So when I see var name string, I'm literally telling Go: I need a container called name, and it will hold string type data?" Ethan asked.

"Exactly," Eleanor smiled. "And Go will enforce that. Try to put a number in name later, and Go will refuse to compile. The type is a promise you make, and Go holds you to it."

"That seems strict."

"It's protective. In Python, you could accidentally assign a number to a variable that used to hold a string, and Python would shrug and let you do it. Then three hundred lines later, your program crashes because you tried to capitalize a number. Go says no—if you declared it as a string, it stays a string. You can't shoot yourself in the foot accidentally."

Eleanor pulled out a piece of paper. "Now, let me show you something we used to do before computers were cheap. We'd trace through the code by hand, checking our work before we ever submitted it to run. It's called desk checking. Watch:"

Step | Line | Code                                              | Variables
-----|------|---------------------------------------------------|---------------------------
  1  |  5   | var name string = "Ethan"                         | name = "Ethan"
  2  |  6   | var age int = 23                                  | name = "Ethan", age = 23
  3  |  8   | fmt.Println("Hello! My name is " + name + ".")    | name = "Ethan", age = 23
     |      | [Prints: Hello! My name is Ethan.]                |
  4  |  9   | fmt.Println("I am", age, "years old.")            | name = "Ethan", age = 23
     |      | [Prints: I am 23 years old.]                      |
  5  |  11  | age = age + 1                                     | name = "Ethan", age = 24
  6  |  12  | fmt.Println("Next year I'll be", age, ".")        | name = "Ethan", age = 24
     |      | [Prints: Next year I'll be 24 .]                  |
Enter fullscreen mode Exit fullscreen mode

"See?" Eleanor tapped the table. "At each step, you can see exactly what the computer knows. This is how you debug with your brain instead of running the code fifty times hoping to spot the problem."

Ethan studied the table. "So at step 5, age changes from 23 to 24."

"Exactly. The variable is reassigned. And notice—we didn't use var again on line 11. We only use var when we're creating a new variable. After that, we just use the name."

"That makes sense," Ethan said. "You only introduce yourself once."

Eleanor's eyes lit up. "What a perfect way to think about it. Yes—var name string = "Ethan" is the introduction. After that, everyone knows who name is."

She typed something new:

package main

import "fmt"

func main() {
    var greeting string
    fmt.Println(greeting)
}
Enter fullscreen mode Exit fullscreen mode

"What do you think this prints?"

Ethan frowned. "We declared greeting but didn't give it a value. Would it be an error?"

"Good instinct, but no. Watch." She ran the code. The output showed a blank line.

"Go has something called zero values," Eleanor explained. "If you declare a variable but don't initialize it, Go gives it a sensible default. For strings, that's an empty string—literally nothing. For integers, it's zero. For booleans, it's false. You never have uninitialized garbage like in C."

"That's... actually really nice," Ethan admitted.

"Go doesn't want you to fail," Eleanor said. "It wants you to succeed. So it gives you reasonable defaults, clear error messages, and a compiler that catches mistakes before they become bugs."

She pulled the laptop back. "Now, let me show you the shortcut I mentioned. Go can infer types:"

package main

import "fmt"

func main() {
    name := "Ethan"
    age := 23

    fmt.Println("Hello! My name is", name + ".")
    fmt.Println("I am", age, "years old.")
}
Enter fullscreen mode Exit fullscreen mode

"What's different?"

"The := symbol!" Ethan pointed. "Instead of var name string =, you just wrote name :=."

"Exactly. The := operator declares a variable and assigns it a value, and Go figures out the type from what you assigned. name := "Ethan" creates a string variable because "Ethan" is a string. age := 23 creates an int because 23 is an integer."

"So I could always use :=?"

"Almost always. There are two restrictions: First, := only works inside functions. At the package level, you need var. Second, := always creates a new variable. If name already exists, := won't work—you'd just use = to assign a new value."

Eleanor leaned back. "Most Go programmers use := for simple cases and var when they need to be explicit about the type. For instance:"

var percentage float64 = 0
Enter fullscreen mode Exit fullscreen mode

"If I wrote percentage := 0, Go would make it an int because 0 is an integer. But I need a float64 for decimal math. So I use var to be explicit."

"That makes sense," Ethan said. "Use the shortcut when it's obvious, be explicit when you need control."

"Precisely." Eleanor smiled. "You're thinking like a Go programmer already. The language encourages clarity. Sometimes that means being verbose. Sometimes that means being concise. But always, it means being clear."

She closed the laptop. "Let's talk about the basic types you'll use most often:"

She wrote in her notebook:

int        - whole numbers (23, -5, 1000)
float64    - decimals (3.14, -0.5, 2.0)
string     - text ("Hello", "Ethan", "")
bool       - true or false
Enter fullscreen mode Exit fullscreen mode

"These are the foundations. Later you'll learn about more specialized types—int32, uint, float32, and others—but these four will handle most of what you need starting out."

"Why float64 and not just float?"

"Because Go wants you to know how much precision you're using. A float64 uses 64 bits of memory and gives you about 15 decimal digits of precision. There's also float32 with less precision but using less memory. Go doesn't hide these details—it trusts you to make informed decisions."

Ethan sipped his coffee, which had grown lukewarm. "This is different from Python."

"Very different. Python says 'I'll handle the details, you just write code.' Go says 'here are the details, you make the choice.' Neither approach is wrong—they're designed for different philosophies." Eleanor stood and moved to the shelves. "Python optimizes for rapid development. Go optimizes for long-term maintenance and clarity."

She pulled down a thin volume—the same one with the gopher on the cover from yesterday. "Rob Pike, one of Go's creators, worked on Unix at Bell Labs. He watched programmers struggle with C's complexity and C++'s baroque abstractions. Go was designed to be simple enough that you could hold the entire language in your head."

"Can you really?"

"Give it a few months. You'll be surprised." Eleanor returned to her seat. "Go has no inheritance, no generics until recently, no exceptions, no implicit type conversions. Every feature was carefully considered and most were rejected. What remains is a small, powerful language that does exactly what it says it does."

The afternoon light had shifted, painting the oak shelves in amber and gold. Eleanor finished her coffee—long since cold, but she didn't seem to mind.

"Next time," she said, "we'll talk about functions. How to write them, how to call them, and why Go's approach to multiple return values is one of its greatest gifts."

"Multiple return values?" Ethan's eyes widened.

"A function can return more than one thing. In fact, it's how Go handles errors—no exceptions, no try-catch blocks. Just honest, explicit return values that you can't ignore." She smiled. "But that's for next time. For now, practice what we learned today. Declare some variables. Change their values. Print them out. Get comfortable with the idea that every piece of data has a name and a type."

Ethan gathered his things, but paused at the foot of the stairs. "Eleanor?"

"Yes?"

"In Python, I always felt like I was guessing. Like I'd write something and hope it worked. But with Go... it feels like the language is helping me."

Eleanor's expression softened. "That's because it is. Go was designed by people who cared about the programmers who would use it. Every decision—the strict typing, the clear error messages, the refusal to compile unused code—is meant to catch mistakes before they become problems. The language is on your side, Ethan. Trust it."

He climbed the stairs, the autumn sun warming the marble foyer. Tomorrow he would return, and Eleanor would teach him about functions. But today, he understood something fundamental: in Go, things had names and types, and that wasn't a restriction—it was a kindness.


Key Concepts from Chapter 2

Variable declarations: Go requires you to declare variables with var name type = value or use the shortcut := value which infers the type.

Types are explicit: Every variable has a type (int, string, float64, bool), and Go enforces it strictly. No accidental type mixing.

Zero values: Uninitialized variables get sensible defaults—empty string for strings, 0 for numbers, false for booleans. No garbage values.

Declaration vs assignment: Use var or := to create a new variable. Use = alone to assign to an existing variable.

The := shortcut: Declares and assigns in one step, with type inference. Only works inside functions.

Type safety: Go won't let you assign the wrong type to a variable. This catches bugs at compile time instead of runtime.

Clarity over cleverness: Go's explicit typing might feel verbose at first, but it makes code easier to read and maintain over time.


Next chapter: Functions and the Power of Return Values—where Ethan learns that Go functions can return multiple values, and Eleanor explains why this changes everything about error handling.


Aaron Rose is a software engineer and technology writer at tech-reader.blog and the author of Think Like a Genius.

Top comments (0)