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
- Learn about control structures
- Explore functions
- Study interfaces
- Practice with generics