Go Data Types

Su Suriya Ravichandran Updated 14 Sep 2026
7 min read ·Lesson 8 of 12

A data type defines what kind of value a variable can hold, how much memory it occupies, and what operations are valid on it. Because Go is statically typed, every variable's type is fixed once declared — you cannot later assign a string to a variable that was declared as an int.

What Data Types Determine

  • The category of data — number, text, true/false, and so on.
  • The amount of memory allocated to store the value.
  • The operations you're allowed to perform (you can add two int values, but not an int and a string, without an explicit conversion).

The Three Basic Categories

Go's basic types fall into three groups: boolean, numeric, and string.

1. Boolean (bool)

Holds exactly one of two values: true or false.

2. Numeric Types

  • Integers: int, int8, int16, int32, int64
  • Unsigned integers: uint, uint8, uint16, uint32, uint64
  • Floating-point: float32, float64
  • Complex numbers: complex64, complex128 (used for scientific and engineering computation; rarely needed in typical application code)

3. String (string)

A sequence of characters (text), written between double quotes.

package main

import "fmt"

func main() {
    isAvailable := true
    quantity := 12
    price := 49.99
    productName := "Wireless Mouse"

    fmt.Println("Available:", isAvailable)
    fmt.Println("Quantity:", quantity)
    fmt.Println("Price:", price)
    fmt.Println("Product:", productName)
}

Type Inference

When you use := or omit an explicit type with var, Go infers the type from the value:

package main

import "fmt"

func main() {
    count := 100      // inferred as int
    rating := 4.5      // inferred as float64
    message := "Hello" // inferred as string

    fmt.Printf("%T\n", count)
    fmt.Printf("%T\n", rating)
    fmt.Printf("%T\n", message)
}

Expected output:

int
float64
string

Why Data Types Matter

  • They let the compiler catch mismatched-type mistakes before the program ever runs.
  • They let Go allocate exactly the right amount of memory for a value.
  • They document intent — a function that takes a uint is telling its caller "this should never be negative."

Boolean Data Type

A bool variable is declared with the bool type, and Go's usual type inference applies here too:

package main

import "fmt"

func main() {
    var isActive bool = true   // explicit type
    var isVerified = false     // type inferred
    var isCompleted bool       // no initial value — defaults to false
    isAvailable := true        // short declaration

    fmt.Println("Active:", isActive)
    fmt.Println("Verified:", isVerified)
    fmt.Println("Completed:", isCompleted)
    fmt.Println("Available:", isAvailable)
}

An uninitialized bool always defaults to false — Go never leaves it undefined. Booleans are most often produced by comparisons rather than typed directly:

package main

import "fmt"

func main() {
    age := 18

    isAdult := age >= 18
    hasPermission := false

    fmt.Println("Is adult:", isAdult)
    fmt.Println("Has permission:", hasPermission)
}

Integer Types

Go integers store whole numbers — values with no decimal point — and come in two families: signed (can be negative) and unsigned (zero or positive only).

If you don't specify a size, Go's default integer type is simply int, whose size (32 or 64 bits) depends on the platform the program is compiled for — on virtually all modern desktop and server systems, that means 64 bits.

Signed Integer Types

package main

import "fmt"

func main() {
    temperature := -12
    score := 98

    fmt.Printf("Temperature: %v (Type: %T)\n", temperature, temperature)
    fmt.Printf("Score: %v (Type: %T)\n", score, score)
}
TypeSizeRange
intPlatform-dependentTypically 64-bit range on modern systems
int88 bits-128 to 127
int1616 bits-32,768 to 32,767
int3232 bits-2,147,483,648 to 2,147,483,647
int6464 bits-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

Unsigned Integer Types

Unsigned types store only non-negative values, which makes them a natural fit for things like counts or byte sizes that can never logically be negative:

package main

import "fmt"

func main() {
    itemCount := uint(150)
    maxUsers := uint16(5000)

    fmt.Printf("Items: %v (Type: %T)\n", itemCount, itemCount)
    fmt.Printf("Max Users: %v (Type: %T)\n", maxUsers, maxUsers)
}
TypeSizeRange
uintPlatform-dependentTypically 64-bit range on modern systems
uint88 bits0 to 255
uint1616 bits0 to 65,535
uint3232 bits0 to 4,294,967,295
uint6464 bits0 to 18,446,744,073,709,551,615

Choosing an Integer Type

  • Use plain int for general-purpose values — it's the idiomatic default in Go, and most of the standard library expects it.
  • Reach for a sized type (int8, int32, uint16, and so on) only when memory layout matters, such as when working with binary file formats, network protocols, or very large slices where every byte counts.
  • Use an unsigned type only when a negative value would be logically meaningless — and be aware that subtracting past zero on an unsigned type wraps around to a very large number instead of going negative, which is a common source of subtle bugs.

Floating-Point Types

Floating-point types store numbers with a fractional part, such as 3.14, -0.75, or values in scientific notation like 1.2e6.

TypeSizeApproximate range
float3232-bit±3.4 × 10³⁸, roughly 7 significant decimal digits
float6464-bit±1.8 × 10³⁰⁸, roughly 15–17 significant decimal digits

Go's default floating-point type — used whenever you write a decimal literal without specifying otherwise — is float64.

package main

import "fmt"

func main() {
    temperature := float32(36.6)
    pressure := float32(101.325)

    fmt.Printf("Temperature: %v (Type: %T)\n", temperature, temperature)
    fmt.Printf("Pressure: %v (Type: %T)\n", pressure, pressure)
}
package main

import "fmt"

func main() {
    distance := 1.496e+11 // roughly the Earth–Sun distance, in meters
    pi := 3.141592653589793

    fmt.Printf("Distance: %v (Type: %T)\n", distance, distance)
    fmt.Printf("Pi value: %.10f (Type: %T)\n", pi, pi)
}

Scientific notation is written with e or E:

package main

import "fmt"

func main() {
    smallValue := 5.2e-3 // 0.0052
    largeValue := 9.1e+6 // 9,100,000

    fmt.Println("Small:", smallValue)
    fmt.Println("Large:", largeValue)
}

Choosing between float32 and float64: default to float64 unless you have a specific reason not to — it's what the standard library and most third-party code expect, and it avoids the precision loss float32 introduces. Reach for float32 only when memory is genuinely tight, such as large numeric datasets or graphics buffers.

Important note on precision: like almost every mainstream language, Go's floating-point types cannot represent every decimal value exactly (this is a consequence of binary floating-point representation, defined by the IEEE 754 standard — not a Go-specific limitation). A calculation like 0.1 + 0.2 will print as 0.30000000000000004, not 0.3. For money or other values requiring exact decimal precision, store amounts as integers (e.g., cents) or use a decimal library rather than float64.

String Data Type

A string stores text — a sequence of characters enclosed in double quotes.

package main

import "fmt"

func main() {
    var greeting string = "Welcome!"
    var emptyMessage string // defaults to ""
    title := "Go Programming"

    fmt.Printf("Greeting: %q (Type: %T)\n", greeting, greeting)
    fmt.Printf("Empty Message: %q (Type: %T)\n", emptyMessage, emptyMessage)
    fmt.Printf("Title: %q (Type: %T)\n", title, title)
}

An uninitialized string's zero value is "" — an empty string, which is a valid, usable string, not a null or missing value.

String Characteristics

  • Strings are immutable: once created, a string's contents cannot be changed in place. Operations that appear to "modify" a string, like concatenation, actually create a new string.
  • Internally, a Go string is a read-only sequence of bytes, conventionally interpreted as UTF-8-encoded text. This matters once you start indexing into strings with non-ASCII characters — a topic covered in more depth once you reach string manipulation and runes.

Concatenation

package main

import "fmt"

func main() {
    firstName := "Arjun"
    lastName := "Kumar"

    fullName := firstName + " " + lastName

    fmt.Println("Full Name:", fullName)
}

Raw String Literals

Strings wrapped in backticks (`) instead of double quotes are called raw string literals. They preserve line breaks and ignore escape sequences entirely, which makes them convenient for multi-line text, regular expressions, or embedded JSON/SQL snippets:

package main

import "fmt"

func main() {
    message := `This is a
multi-line string
in Go.`

    fmt.Println(message)
}

Common mistake: trying to modify a string's characters directly with index assignment, like greeting[0] = 'h'. Because strings are immutable, this does not compile. To change a string's content, build a new string instead — for example, using the strings package or converting to a []byte / []rune, modifying that, and converting back.

0 Comments

Reviewed before they appear

No comments yet.

Go Lang
Ask about this post
AI Ask about this post

Ask questions about Go Data Types and get answers drawn from it.

Signed-in readers only.