New: Try Voli The Bear, Fast package manager (and not only) for Windows
Updated Jun 19, 2026 Edit on GitHub

Syntax, Values & Types

Real programs hold values - a name, a count, a price - and do things with them. In Go, every value has a type, and the language is strict about it in a way that feels heavy at first but becomes a safety net fast.

What "statically typed" actually means

Go is statically typed: every variable has a fixed type, known and checked when your code is compiled, before it ever runs. A variable holding a number can never later hold text - the compiler verifies this up front.

Coming from Python or JavaScript, you might expect a variable to be a box you can drop anything into. In Go it's a box with a shape - number-shaped, text-shaped - and the compiler checks everything you put in fits. Bugs like "I thought this was a number but it was the text '42'" can't survive to runtime; they're caught while you build.

📝 Terminology. A type is the kind of value something is - an integer, a piece of text, a true/false. Static means "checked at compile time" (vs. dynamic, "checked while running"). Go checks early, so the running program never has to wonder what type something is.

var - the explicit way to declare a value

The full, spelled-out way to create a variable uses the var keyword:

package main

import "fmt"

func main() {
	var name string = "Ada"
	var age int = 36
	fmt.Println(name, "is", age)
}
$ go run main.go
Ada is 36

var name string = "Ada" reads left to right as "declare a variable called name, of type string (text), and set it to "Ada"." Same for age, of type int. fmt.Println printed all three pieces with a space between each - the types are written right there, so there's no ambiguity about what each box holds.

Go can usually figure the type out from the value, so you can drop it and let the compiler infer it:

var name = "Ada"   // Go sees "Ada" is text, so name is a string
var age = 36       // Go sees 36 is a whole number, so age is an int

name is still a string, age still an int - you just didn't spell it out. The variable is no less typed; the compiler inferred it.

:= - the short declaration you'll use most

Inside a function, Go gives you an even shorter form that declares and assigns at once:

package main

import "fmt"

func main() {
	name := "Ada"
	age := 36
	fmt.Println(name, "is", age)
}

name := "Ada" is the short variable declaration. The := means "create a new variable and set it" - Go infers the type from the value, exactly like var name = "Ada" but more compact. This is the form you'll see and write most in real Go code.

⚠️ Gotcha - := only works inside functions. At the top level of a file, you must use var. Writing count := 0 outside a function is a compile error: := is shorthand for a local working variable, and the top level is for declaring package-level things, var's job. Rule of thumb: inside func:=; outside → var.

The basic types you'll actually use

These cover almost everything early on:

  • int - a whole number, positive or negative (-3, 0, 42). Your default for counting.
  • float64 - a number with a decimal point (3.14, -0.5). The 64 is how many bits it uses; the normal choice for fractional numbers.
  • string - text, written in double quotes ("hello").
  • bool - a truth value, either true or false. Named after George Boole.

There are more (smaller and larger integers, an unsigned variety, a single-character rune), but reach for those only with a specific reason. int, float64, string, and bool will take you a long way.

Zero values - why Go variables are never "undefined"

In some languages, a variable you declare but don't set holds garbage, or a null/undefined that blows up the moment you touch it. Go refuses to leave a variable empty. Every type has a defined zero value, and a freshly declared variable starts there automatically.

package main

import "fmt"

func main() {
	var count int
	var price float64
	var label string
	var ready bool
	fmt.Println(count, price, label, ready)
}
$ go run main.go
0 0  false

Four variables, none set, yet all start at sensible, predictable values: int at 0, float64 at 0, string at "" (the blank gap between 0 and false in the output), bool at false. Nothing is "undefined" - you can read any of them immediately without a crash.

💡 Key point. The zero value rule means there is no uninitialized-variable surprise in Go. Declare var count int and you know it's 0 - a whole class of "why is this null?" bugs never happens. Worth memorizing: numbers → 0, strings → "", bools → false. (We'll meet nil - the zero value for a few special types - in phase 3; it follows the same rule.)

The other unused-thing error: declared and not used

You met unused imports in phase 1. Variables have the same rule: declare one and never read it, and Go won't compile.

package main

func main() {
	total := 100
}
$ go run main.go
./main.go:4:2: declared and not used: total

total was never used, so the compiler stopped and pointed at it (main.go:4:2). Fix: use the variable (print it, return it, calculate with it) or delete the line - same philosophy as unused imports.

Printing properly with Println and Printf

You've been using fmt.Println, which prints its arguments with spaces between them and a trailing newline - great for quick output. For control over the format, reach for fmt.Printf ("print formatted"):

package main

import "fmt"

func main() {
	name := "Ada"
	age := 36
	fmt.Printf("%s is %d years old.\n", name, age)
}
$ go run main.go
Ada is 36 years old.

Printf takes a format string with verbs - placeholders starting with % - filled in by the values that follow, in order. %s means "put a string here," %d means "put a whole number (a decimal integer) here," and \n is the newline character (Printf, unlike Println, doesn't add one for you). Verbs worth knowing now:

  • %s - a string
  • %d - an integer
  • %f - a float (%.2f rounds to 2 decimal places)
  • %v - any value in its default form (the helpful catch-all when you're not sure)
  • %t - a boolean (true/false)

⚠️ Gotcha. Mismatched verbs don't crash Go - it prints a visible complaint right in the output, like %!d(string=Ada), meaning "you asked for a %d integer but handed me the string Ada." Ugly on purpose, so you spot the mismatch instantly instead of shipping wrong output.

Recap

  1. Go is statically typed: every variable has a fixed type, checked when you compile.
  2. var name type = value is the explicit declaration; drop the type to let Go infer it.
  3. := declares-and-assigns in one step and is what you'll use most - but only inside functions; use var at the top level.
  4. The everyday types: int, float64, string, bool.
  5. Zero values mean nothing is ever uninitialized: numbers 0, strings "", bools false.
  6. Unused variables are compile errors (declared and not used), just like unused imports.
  7. fmt.Println for quick output; fmt.Printf with verbs (%s %d %f %v %t) for formatted output.

Next: from single values to collections - arrays, the slices you'll actually use, and maps for looking things up by name.


← Phase 1: Install & Your First Program · Guide overview · Phase 3: Collections →

Before the quiz: without looking back, say (or jot down) the core idea of this phase in your own words.

Check your understanding 3 questions

1. Go being statically typed means...

2. A 'zero value' in Go means...

3. The short declaration `:=` can be used...