Data Types & Zero Values

beginner go types

A data type tells Go what kind of value a variable holds — a number, some text, a true/false, and so on. Go is statically typed, so every value has a type, and the compiler checks it.

Let’s go through the basic types first, then hit the big interview favorite: zero values.

The basic types

var i int = 42        // platform-sized integer (32 or 64 bit)
var big int64 = 99999 // explicitly 64-bit integer
var price float64 = 9.99 // floating-point number (use float64 by default)
var name string = "Go"   // text
var ok bool = true       // true or false
var b byte = 'A'         // alias for uint8 — a single raw byte (65)
var r rune = ''        // alias for int32 — a single Unicode character

A few notes that trip people up:

  • int sizes itself to the machine (64-bit on modern systems). When in doubt, just use int.
  • float64 is the default float — prefer it over float32 unless we have a memory reason.
  • byte is just a nicer name for uint8. rune is just a nicer name for int32. They exist to make intent clear.

byte vs rune (the string gotcha)

In simple language, a byte is one raw 8-bit chunk, while a rune is one full character (which might be several bytes).

This matters because Go strings are UTF-8 encoded. An emoji or a Hindi character takes multiple bytes but is a single rune.

s := "héllo"
fmt.Println(len(s))           // 6 — counts BYTES, not characters! (é is 2 bytes)
fmt.Println(len([]rune(s)))   // 5 — converting to runes counts CHARACTERS

for i, r := range s {
	// range over a string gives us runes, not bytes
	fmt.Printf("%d: %c\n", i, r)
}

So len(string) gives bytes, not character count. Remember that — it’s a classic gotcha.

The zero value concept

Here’s the Go-specific idea interviewers love. In Go, every variable is automatically given a “zero value” if we don’t initialize it. There’s no such thing as an uninitialized variable holding garbage memory.

Think of it like this: Go refuses to hand us a box with random junk inside. It always gives us a clean, sensible default.

This kills a whole category of bugs. In C, an uninitialized int could be any random number. In Java, an uninitialized object is null and blows up. In Go, things just start at a safe default.

Here’s what each type defaults to:

Type
Zero Value
int, int64, byte, rune
0
float64
0.0
bool
false
string
"" (empty string)
pointer, slice, map, channel, func, interface
nil
var n int       // 0
var f float64   // 0.0
var s string    // "" (empty, not nil!)
var ready bool  // false
var p *int      // nil

fmt.Println(n, f, s == "", ready, p == nil) // 0 0 true false true

Notice that a string’s zero value is the empty string "", not nil. Only the reference-y types (pointers, slices, maps, channels, funcs, interfaces) are nil.

This means we can declare a variable and start using it safely. For example, a zero-value int is ready to be added to, and a zero-value bool is already false — no setup needed.

Interview soundbite

Go has the usual basic types, plus byte (alias for uint8) and rune (alias for int32) for working with bytes versus full Unicode characters in strings. The killer concept is zero values: every variable gets a sane default automatically — 0 for numbers, "" for strings, false for bools, and nil for reference types — so there’s no such thing as an uninitialized garbage value in Go.