LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 917 min read

Data Types

Explore Go's built-in data types — integers, floats, strings, booleans, bytes, and runes — and when to use each one.

Introduction

Go is a statically typed language, and its built-in data types are the building blocks for every variable you'll declare. This lesson covers numeric types, strings, booleans, and the two Go types beginners find most confusing — byte and rune.

Integer Types

Go provides both platform-dependent and fixed-size integer types. `int` is the general-purpose choice for most code, sized automatically to 32 or 64 bits depending on the platform (64-bit on virtually all modern systems).

package main
import "fmt"
func main() {
var age int = 30
var smallNumber int8 = 120
var bigCounter int64 = 9_000_000_000
fmt.Println(age, smallNumber, bigCounter)
}
Output

Click Run to see what this code prints.

Go also provides unsigned integer types (uint8, uint16, uint32, uint64) for values that are never negative, such as counts or byte data.

Floating-Point Types

Go has two floating-point types: `float32` and `float64`. `float64` is the default and recommended choice for almost all floating-point math, offering much greater precision.

package main
import "fmt"
func main() {
price := 19.99 // inferred as float64
var rate float32 = 0.05
fmt.Println(price, rate)
}
Output

Click Run to see what this code prints.

The string Type

A Go `string` is an immutable sequence of bytes, typically holding UTF-8 encoded text. Strings are declared with double quotes for interpreted strings (supporting escape sequences like \n) or backtick raw strings for literal, multi-line text with no escaping.

package main
import "fmt"
func main() {
greeting := "Hello, \"Go\"!\n"
fmt.Print(greeting)
fmt.Println(len("Hello")) // number of bytes
}
Output

Click Run to see what this code prints.

The bool Type

A `bool` holds exactly one of two values: `true` or `false`. Its zero value is `false`. Unlike some languages, Go does not allow other types (like integers) to be used directly as booleans — there is no implicit truthiness conversion.

package main
import "fmt"
func main() {
isReady := true
hasErrors := false
fmt.Println(isReady, hasErrors, isReady && !hasErrors)
}
Output

Click Run to see what this code prints.

byte and rune

`byte` is an alias for `uint8`, representing a single byte of data (0–255) — commonly used when working with raw binary or ASCII text. `rune` is an alias for `int32`, representing a single Unicode code point — used when you need to work correctly with international text, where a single visible character can take more than one byte in UTF-8.

package main
import "fmt"
func main() {
word := "café"
fmt.Println("byte length:", len(word)) // counts bytes
fmt.Println("rune length:", len([]rune(word))) // counts characters
for i, r := range word {
fmt.Printf("index %d: %c\n", i, r)
}
}
Output

Click Run to see what this code prints.

Notice that "café" is 5 bytes but only 4 characters — the "é" takes 2 bytes in UTF-8 but is a single rune. Ranging over a string in Go automatically iterates rune by rune (correctly handling multi-byte characters), which is exactly why the last index jumps from 3 rather than continuing sequentially.

Type Sizes at a Glance

TypeSizeTypical Use
int32 or 64 bits (platform dependent)General-purpose whole numbers
int8 / int16 / int32 / int64Fixed 8/16/32/64 bitsWhen exact size matters (e.g. binary formats)
float6464 bitsDefault choice for decimal numbers
float3232 bitsMemory-constrained or graphics-related code
bool1 byteTrue/false flags
byte (= uint8)8 bitsRaw binary data, ASCII text
rune (= int32)32 bitsUnicode characters, especially non-ASCII text

Choosing the Right Type

  • Default to `int` for whole numbers and `float64` for decimals unless you have a specific reason not to.
  • Use fixed-size integer types (int32, int64, etc.) when interoperating with binary formats, network protocols, or file structures.
  • Use `rune` (not `byte`) whenever you need to process text character by character, especially for non-English text.
  • Use `byte` when working with raw data such as file contents or network payloads.

Common Mistakes

Avoid These Mistakes
  • Using `len(str)` and assuming it returns the character count — it returns the byte count, which differs for non-ASCII text.
  • Treating `byte` and `rune` as interchangeable — a byte is 8 bits, a rune can represent Unicode characters that span multiple bytes.
  • Assuming `int` is always 64-bit — its size is platform-dependent (though 64-bit on virtually all modern systems).
  • Using `float32` by default — `float64` is almost always the better choice for precision.

Best Practices

  • Default to `int` and `float64` unless you have a concrete reason to pick a more specific type.
  • When iterating over text that might contain non-ASCII characters, range over the string (which yields runes) instead of indexing bytes directly.
  • Use `[]rune(str)` when you need an accurate character count for international text.
  • Reach for fixed-width integer types only when size genuinely matters, such as binary file formats.

Frequently Asked Questions

byte is an alias for uint8 and represents a single 8-bit value. rune is an alias for int32 and represents a single Unicode code point, which may be composed of multiple bytes in UTF-8.

Go strings are UTF-8 encoded byte sequences, and len() counts bytes. The character "é" takes 2 bytes in UTF-8, so the 4-character string "café" totals 5 bytes.

Use float64 by default — it offers much higher precision and is the standard choice in idiomatic Go code. Reach for float32 only when memory constraints specifically require it.

Key Takeaways

  • Go's core numeric types are int and float64 for general use, plus fixed-size variants when needed.
  • Strings are immutable, UTF-8 byte sequences; len() returns byte count, not character count.
  • bool holds only true or false, with no implicit conversions from other types.
  • byte (alias for uint8) represents raw bytes; rune (alias for int32) represents Unicode characters.
  • Ranging over a string in Go yields runes, correctly handling multi-byte characters.

Summary

You now know Go's core built-in types and when to reach for each one — including the byte/rune distinction that trips up many newcomers. Next, you'll learn how to convert between these types explicitly, since Go never does it implicitly for you.

Next Lesson →

Type Conversion