1. go
  2. /basics
  3. /data-types

Understanding Data Types in Go Programming

Go provides a rich set of data types to work with. This guide covers all the built-in data types and how to use them effectively.

Basic Types

Numeric Types

// Integer types
var (
    a int     = 42    // Platform dependent (32 or 64 bit)
    b int8    = 127   // -128 to 127
    c int16   = 32767 // -32768 to 32767
    d int32   = 2147483647
    e int64   = 9223372036854775807
)

// Unsigned integers
var (
    f uint    = 42    // Platform dependent
    g uint8   = 255   // 0 to 255 (byte is an alias for uint8)
    h uint16  = 65535 // 0 to 65535
    i uint32  = 4294967295
    j uint64  = 18446744073709551615
)

// Floating point
var (
    k float32 = 3.14159
    l float64 = 3.14159265359
)

// Complex numbers
var (
    m complex64  = 1 + 2i
    n complex128 = 1.1 + 2.2i
)

Boolean Type

var (
    isTrue  = true
    isFalse = false
)

// Boolean operations
result := isTrue && isFalse  // AND
result = isTrue || isFalse   // OR
result = !isTrue            // NOT

String Type

// String declaration
var (
    name     = "Go"
    message  = `Multi-line
                string`
)

// String operations
length := len(name)           // Length
char := name[0]              // Get byte at index
slice := name[0:2]           // Substring
combined := name + " Lang"   // Concatenation

// String formatting
formatted := fmt.Sprintf("Hello, %s!", name)

Rune Type

// Rune (int32) represents a Unicode code point
var (
    r rune = 'A'
    s rune = '世'
)

// String iteration by rune
for i, r := range "Hello, 世界" {
    fmt.Printf("%d: %c\n", i, r)
}

Composite Types

Arrays

// Fixed-size array
var numbers [5]int = [5]int{1, 2, 3, 4, 5}

// Short declaration
scores := [3]int{10, 20, 30}

// Array with size determined by initializer
days := [...]string{"Mon", "Tue", "Wed"}

// Accessing elements
first := numbers[0]
numbers[1] = 10

// Multi-dimensional array
matrix := [2][3]int{
    {1, 2, 3},
    {4, 5, 6},
}

Slices

// Slice declaration
var numbers []int

// Create slice with make
numbers = make([]int, 5, 10)  // length 5, capacity 10

// Slice literal
fruits := []string{"apple", "banana", "orange"}

// Slice operations
numbers = append(numbers, 1, 2, 3)
slice := numbers[1:4]  // Half-open range
copy(dest, src)       // Copy elements

// Slice tricks
reversed := numbers[len(numbers)-1:0:-1]  // Reverse
cleared := numbers[:0]                    // Clear

Maps

// Map declaration
var scores map[string]int

// Create map with make
scores = make(map[string]int)

// Map literal
colors := map[string]string{
    "red":   "#ff0000",
    "green": "#00ff00",
    "blue":  "#0000ff",
}

// Map operations
colors["yellow"] = "#ffff00"  // Add/update
delete(colors, "red")         // Delete
value, exists := colors["red"]  // Check existence

// Iterate over map
for key, value := range colors {
    fmt.Printf("%s: %s\n", key, value)
}

Structs

// Struct declaration
type Person struct {
    Name    string
    Age     int
    Address struct {
        Street string
        City   string
    }
}

// Create struct
person := Person{
    Name: "Alice",
    Age:  30,
}

// Anonymous struct
point := struct {
    X, Y int
}{10, 20}

// Nested struct
type Employee struct {
    Person    // Embedded struct
    Company string
}

Type Conversions

Basic Type Conversion

// Numeric conversions
var (
    i int     = 42
    f float64 = float64(i)    // int to float64
    u uint    = uint(f)       // float64 to uint
)

// String conversions
import "strconv"

s1 := strconv.Itoa(i)        // Int to string
s2 := strconv.FormatFloat(f, 'f', 2, 64)  // Float to string
i2, err := strconv.Atoi("42")  // String to int
f2, err := strconv.ParseFloat("3.14", 64)  // String to float

Type Assertions

var i interface{} = "hello"

// Type assertion
if str, ok := i.(string); ok {
    fmt.Printf("String: %s\n", str)
}

// Type switch
switch v := i.(type) {
case string:
    fmt.Printf("String: %s\n", v)
case int:
    fmt.Printf("Integer: %d\n", v)
default:
    fmt.Printf("Unknown type\n")
}

Custom Types

Type Definitions

// Type definition
type UserID string
type Celsius float64
type Callback func(string) error

// Methods on custom types
func (c Celsius) Fahrenheit() float64 {
    return float64(c)*1.8 + 32
}

// Usage
var temp Celsius = 100
fmt.Printf("%.2f°C is %.2f°F\n", temp, temp.Fahrenheit())

Type Aliases

// Type alias
type byte = uint8
type rune = int32

// Custom type alias
type Text = string

Zero Values

var (
    intZero     int         // 0
    floatZero   float64     // 0.0
    boolZero    bool        // false
    stringZero  string      // ""
    pointerZero *int        // nil
    sliceZero   []int       // nil
    mapZero     map[string]int  // nil
    chanZero    chan int    // nil
    funcZero    func()      // nil
    interfaceZero interface{}  // nil
)

Best Practices

1. Type Selection

// Good: Use specific types
type UserID string
type Temperature float64

// Avoid: Using generic types
type ID interface{}
type Value interface{}

2. Type Consistency

// Good: Consistent type usage
type Money struct {
    Amount   decimal.Decimal
    Currency string
}

// Avoid: Mixed numeric types
type Price struct {
    Amount   float64  // Potential precision issues
    Discount int
}

3. Error Types

// Good: Custom error types
type ValidationError struct {
    Field string
    Error string
}

func (v *ValidationError) Error() string {
    return fmt.Sprintf("%s: %s", v.Field, v.Error)
}

Common Patterns

1. Option Types

type Option[T any] struct {
    value T
    valid bool
}

func Some[T any](value T) Option[T] {
    return Option[T]{value: value, valid: true}
}

func None[T any]() Option[T] {
    return Option[T]{valid: false}
}

2. Result Types

type Result[T any] struct {
    value T
    err   error
}

func Success[T any](value T) Result[T] {
    return Result[T]{value: value}
}

func Failure[T any](err error) Result[T] {
    return Result[T]{err: err}
}

3. Generic Collections

type Stack[T any] struct {
    items []T
}

func (s *Stack[T]) Push(item T) {
    s.items = append(s.items, item)
}

func (s *Stack[T]) Pop() (T, bool) {
    if len(s.items) == 0 {
        var zero T
        return zero, false
    }
    item := s.items[len(s.items)-1]
    s.items = s.items[:len(s.items)-1]
    return item, true
}

Next Steps

  1. Learn about control structures
  2. Explore functions
  3. Study interfaces
  4. Practice with generics

Additional Resources