Data Types
Go has several basic types including numerics, strings, booleans, arrays, slices, and maps. Let's explore each type in detail.
1. Numeric Types
Integer Types
Signed integers
int8: -128 to 127int16: -32768 to 32767int32: -2147483648 to 2147483647int64: -9223372036854775808 to 9223372036854775807int: Platform dependent (32 or 64 bit)
Unsigned integers
uint8: 0 to 255 (byte is an alias for uint8)uint16: 0 to 65535uint32: 0 to 4294967295uint64: 0 to 18446744073709551615uint: Platform dependent (32 or 64 bit)uintptr: Integer large enough to store any pointer address
Floating-Point Types
float32: IEEE-754 32-bit floating-point numbersfloat64: IEEE-754 64-bit floating-point numbers (default for floating-point)
Complex Numbers
complex64: Complex numbers with float32 real and imaginary partscomplex128: Complex numbers with float64 real and imaginary parts (default for complex)
Floating-Point Formatting
f := 3.14159265359
// Basic formatting
fmt.Printf("Default: %f\n", f) // Default: 3.141593
fmt.Printf("2 decimals: %.2f\n", f) // 2 decimals: 3.14
fmt.Printf("Scientific: %e\n", f) // Scientific: 3.141593e+00
fmt.Printf("Width 10: %10.2f\n", f) // Width 10: 3.14
fmt.Printf("Padded: %010.2f\n", f) // Padded: 0000003.14
// Using strconv
s := strconv.FormatFloat(f, 'f', 2, 64) // "3.14"Examples
package main
import "fmt"
func main() {
// Integer examples
var i int = 42
var i8 int8 = 127
var ui uint = 123
// Floating point examples
var f32 float32 = 3.14
var f64 float64 = 3.141592653589793
// Complex number examples
var c64 complex64 = complex(5, 7) // 5 + 7i
var c128 complex128 = complex(1, 2) // 1 + 2i
fmt.Printf("int: %v, type: %T\n", i, i)
fmt.Printf("int8: %v, type: %T\n", i8, i8)
fmt.Printf("uint: %v, type: %T\n", ui, ui)
fmt.Printf("float32: %v, type: %T\n", f32, f32)
fmt.Printf("float64: %v, type: %T\n", f64, f64)
fmt.Printf("complex64: %v, type: %T\n", c64, c64)
fmt.Printf("complex128: %v, type: %T\n", c128, c128)
}
### Type Conversion
Go requires explicit type conversion between different numeric types:
```go
var i int = 42
var f float64 = float64(i)
var u uint = uint(f)2. Boolean Type
The boolean type bool represents two possible values: true and false.
var isValid bool = true
var isComplete bool // zero value is false
// Boolean operators
and := true && false // false
or := true || false // true
not := !true // false
// Comparison operators return boolean
equals := 5 == 5 // true
greater := 10 > 5 // true
less := 5 < 10 // true3. String Type
Strings in Go are immutable sequences of bytes. This means once a string is created, it cannot be modified.
String Immutability
str := "hello"
// str[0] = 'H' // This will cause a compilation error
// Strings cannot be modified directly
// To modify a string, create a new one
newStr := "H" + str[1:] // Creates a new string "Hello"
// Or convert to byte slice, modify, and convert back
bytes := []byte(str)
bytes[0] = 'H'
newStr = string(bytes) // "Hello"String Performance Considerations
// Bad performance: creates many temporary strings
str := ""
for i := 0; i < 1000; i++ {
str += "a"
}
// Good performance: uses strings.Builder
var builder strings.Builder
for i := 0; i < 1000; i++ {
builder.WriteString("a")
}
result := builder.String()4. Array Type
Arrays in Go have a fixed length and contain elements of the same type.
// Array declaration
var numbers [5]int // Array of 5 integers
colors := [3]string{"red", "green", "blue"}
sizes := [...]int{1, 2, 3, 4, 5} // Size determined by elements
// Accessing and modifying
first := numbers[0] // Get first element
numbers[1] = 10 // Set second element
// Array operations
length := len(numbers) // Get array length
// Multi-dimensional arrays
var matrix [3][4]int // 3x4 matrix
matrix[0][0] = 1 // Set element
// Array iteration
for i, value := range colors {
fmt.Printf("colors[%d] = %s\n", i, value)
}5. Slice Type
Slices are dynamic, flexible views into arrays. Understanding their behavior when copying is crucial.
Slice Behavior and Sharing
// Original slice
original := []int{1, 2, 3, 4, 5}
// Creating a new slice reference (shallow copy)
reference := original // Both slices share the same underlying array
reference[0] = 99 // Changes affect both slices
fmt.Println(original[0]) // Prints: 99
// Creating a slice copy (deep copy)
copySlice := make([]int, len(original))
copy(copySlice, original) // Creates a new independent copy
copySlice[0] = 100 // Only affects the copy
fmt.Println(original[0]) // Prints: 99
fmt.Println(copySlice[0]) // Prints: 100
// Slicing behavior
slice1 := original[1:3] // Creates a view into original
slice1[0] = 200 // Affects original because they share memory
fmt.Println(original[1]) // Prints: 200Slice Capacity Behavior
// Creating a slice with length 3 and capacity 5
slice := make([]int, 3, 5)
fmt.Printf("Length: %d, Capacity: %d\n", len(slice), cap(slice))
// Append within capacity
slice = append(slice, 1) // Uses same backing array
// Append beyond capacity
for i := 0; i < 3; i++ {
slice = append(slice, i)
}
// New backing array is allocated with doubled capacity6. Map Type
Maps in Go are reference types, which affects their copying behavior.
Map Reference Behavior
// Original map
original := map[string]int{"one": 1, "two": 2}
// Creating a reference (not a copy)
reference := original // Both variables refer to the same map
reference["one"] = 100 // Changes affect both maps
fmt.Println(original["one"]) // Prints: 100
// To create a true copy
copy := make(map[string]int)
for k, v := range original {
copy[k] = v
}
copy["one"] = 200 // Only affects the copy
fmt.Println(original["one"]) // Still prints: 100Map Concurrency
// Maps are not safe for concurrent access
// Use sync.Map for concurrent access
var syncMap sync.Map
// Thread-safe operations
syncMap.Store("key", "value")
value, exists := syncMap.Load("key")
syncMap.Delete("key")7. Struct Type
Structs are value types, but can contain reference type fields.
Struct Copy Behavior
type Person struct {
Name string
Age int
Friends []string // Slice is a reference type
}
// Creating a struct
original := Person{
Name: "John",
Age: 30,
Friends: []string{"Alice", "Bob"},
}
// Copying a struct
copy := original // Creates a new struct with copied values
copy.Name = "Jane" // Only affects copy
copy.Age = 25 // Only affects copy
copy.Friends[0] = "Charlie" // Affects both because slice is a reference type
// Deep copy of struct with slices
deepCopy := Person{
Name: original.Name,
Age: original.Age,
Friends: make([]string, len(original.Friends)),
}
copy(deepCopy.Friends, original.Friends)8. Interface Type
Interfaces define behavior by declaring a set of methods.
// Interface declaration
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
// Interface embedding
type ReadWriter interface {
Reader
Writer
}
// Empty interface
var i interface{} // can hold values of any type
i = 42
i = "hello"
i = struct{ name string }{"John"}
// Type assertions
str, ok := i.(string) // safe type assertion
if ok {
fmt.Printf("string value: %s\n", str)
}
// Type switches
switch v := i.(type) {
case int:
fmt.Printf("Integer: %d\n", v)
case string:
fmt.Printf("String: %s\n", v)
default:
fmt.Printf("Unknown type\n")
}Best Practices for Data Type Usage
String Handling
Use strings.Builder for string concatenation in loops
Use bytes.Buffer when working with I/O
Consider using []byte for heavy string manipulation
Slice Management
Pre-allocate slices when size is known
Use copy() for slice copying
Be careful with slice references in long-lived objects
Map Usage
Use make() to initialize maps
Check for existence using two-value assignment
Use sync.Map for concurrent access
Memory Efficiency
Release references to large slices or maps when no longer needed
Use pointer receivers for large structs
Consider using sync.Pool for frequently allocated objects
Type Conversion
Always check for overflow when converting between numeric types
Use strconv package for string conversions
Handle errors in string-to-number conversions
Additional Resources
Last updated
Was this helpful?