Lompat ke konten
Beranda ยป Arrays, Slices, dan Maps: Struktur Data Penting di Go – Pengelolaan Data Collection

Arrays, Slices, dan Maps: Struktur Data Penting di Go – Pengelolaan Data Collection

Struktur Data Penting di Go

Struktur data adalah fondasi dalam pemrograman, dan Go menyediakan tiga struktur data collection yang powerful: Arrays, Slices, dan Maps. Ketiga struktur data ini memiliki karakteristik dan kegunaan yang berbeda, namun saling melengkapi dalam membangun aplikasi Go yang efisien. Artikel ini akan membahas secara mendalam tentang cara kerja, perbedaan, dan best practices dalam menggunakan Arrays, Slices, dan Maps di Go. Saya harapkan sudah mempelajari artikel sebelumnya tentang Functions di Go: Parameter, Return Values, dan Named Returns supaya lebih mudah memahami materi ini. Ini merupakan materi terakhir untuk bagian pemula.

Mengapa Struktur Data Collection Penting di Go?

Go dirancang untuk performa dan kesederhanaan. Struktur data collection di Go mencerminkan filosofi ini dengan memberikan:

  • Performance yang optimal – Memory layout yang efisien
  • Type safety – Compile-time checking untuk mencegah error
  • Simplicity – API yang mudah dipahami dan digunakan
  • Memory efficiency – Manajemen memori yang baik

Mari kita eksplorasi masing-masing struktur data ini secara detail.

Arrays di Go: Fondasi Structure Data

Apa itu Array di Go?

Array di Go adalah struktur data dengan ukuran tetap yang menyimpan elemen-elemen dengan tipe data yang sama. Berbeda dengan bahasa lain, ukuran array di Go adalah bagian dari tipenya.

Deklarasi dan Inisialisasi Array

gopackage main

import "fmt"

func main() {
    // Deklarasi array dengan ukuran 5
    var numbers [5]int
    fmt.Println("Array kosong:", numbers) // Output: [0 0 0 0 0]
    
    // Inisialisasi dengan nilai
    var fruits [3]string = [3]string{"apple", "banana", "orange"}
    fmt.Println("Array fruits:", fruits)
    
    // Inisialisasi singkat
    colors := [4]string{"red", "green", "blue", "yellow"}
    fmt.Println("Array colors:", colors)
    
    // Auto-sizing dengan ...
    auto := [...]int{1, 2, 3, 4, 5}
    fmt.Println("Auto-sized array:", auto)
    fmt.Println("Length:", len(auto)) // Output: 5
}

Operasi Dasar Array

gofunc arrayOperations() {
    numbers := [5]int{10, 20, 30, 40, 50}
    
    // Mengakses elemen
    fmt.Println("First element:", numbers[0])  // Output: 10
    fmt.Println("Last element:", numbers[4])   // Output: 50
    
    // Mengubah nilai elemen
    numbers[2] = 100
    fmt.Println("Modified array:", numbers) // Output: [10 20 100 40 50]
    
    // Iterasi dengan for loop
    fmt.Println("Iterasi dengan index:")
    for i := 0; i < len(numbers); i++ {
        fmt.Printf("Index %d: %d\n", i, numbers[i])
    }
    
    // Iterasi dengan range
    fmt.Println("Iterasi dengan range:")
    for index, value := range numbers {
        fmt.Printf("Index %d: %d\n", index, value)
    }
}

Multidimensional Arrays

gofunc multidimensionalArrays() {
    // Array 2D - Matrix 3x3
    var matrix [3][3]int
    
    // Inisialisasi matrix
    matrix = [3][3]int{
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9},
    }
    
    fmt.Println("Matrix:")
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            fmt.Printf("%d ", matrix[i][j])
        }
        fmt.Println()
    }
    
    // Array 3D
    var cube [2][2][2]int = [2][2][2]int{
        {
            {1, 2},
            {3, 4},
        },
        {
            {5, 6},
            {7, 8},
        },
    }
    
    fmt.Println("Cube[0][1][1]:", cube[0][1][1]) // Output: 4
}

Slices di Go: Dynamic Arrays yang Powerful

Apa itu Slice?

Slice adalah abstraksi di atas array yang memberikan fleksibilitas ukuran dinamis. Slice tidak menyimpan data secara langsung, melainkan referensi ke underlying array.

Anatomy Slice

Slice terdiri dari tiga komponen:

  • Pointer: Menunjuk ke elemen pertama array yang dapat diakses
  • Length: Jumlah elemen dalam slice
  • Capacity: Jumlah elemen dalam underlying array
gofunc sliceAnatomy() {
    // Membuat slice dari array
    arr := [6]int{1, 2, 3, 4, 5, 6}
    slice := arr[1:4] // Slice dari index 1 sampai 3
    
    fmt.Printf("Array: %v\n", arr)
    fmt.Printf("Slice: %v\n", slice)
    fmt.Printf("Length: %d, Capacity: %d\n", len(slice), cap(slice))
    
    // Mengubah slice mempengaruhi array asli
    slice[0] = 100
    fmt.Printf("Array setelah modifikasi slice: %v\n", arr)
}

Cara Membuat Slice

gofunc createSlices() {
    // 1. Slice literal
    numbers := []int{1, 2, 3, 4, 5}
    fmt.Println("Slice literal:", numbers)
    
    // 2. Menggunakan make()
    // make([]type, length, capacity)
    made := make([]int, 5, 10)
    fmt.Printf("Made slice: %v, len: %d, cap: %d\n", made, len(made), cap(made))
    
    // 3. Dari array
    arr := [5]string{"a", "b", "c", "d", "e"}
    slice1 := arr[:]     // Semua elemen
    slice2 := arr[1:4]   // Index 1-3
    slice3 := arr[:3]    // Dari awal sampai index 2
    slice4 := arr[2:]    // Dari index 2 sampai akhir
    
    fmt.Println("slice1:", slice1)
    fmt.Println("slice2:", slice2)
    fmt.Println("slice3:", slice3)
    fmt.Println("slice4:", slice4)
    
    // 4. Nil slice
    var nilSlice []int
    fmt.Println("Nil slice:", nilSlice == nil) // Output: true
}

Operasi Slice yang Powerful

gofunc sliceOperations() {
    // Append - Menambah elemen
    slice := []int{1, 2, 3}
    fmt.Println("Original:", slice)
    
    slice = append(slice, 4, 5, 6)
    fmt.Println("After append:", slice)
    
    // Append slice ke slice
    other := []int{7, 8, 9}
    slice = append(slice, other...)
    fmt.Println("After append slice:", slice)
    
    // Copy slice
    source := []int{1, 2, 3, 4, 5}
    dest := make([]int, len(source))
    copied := copy(dest, source)
    fmt.Printf("Copied %d elements: %v\n", copied, dest)
    
    // Delete element (no built-in delete)
    // Delete index 2
    slice = []int{1, 2, 3, 4, 5}
    index := 2
    slice = append(slice[:index], slice[index+1:]...)
    fmt.Println("After delete index 2:", slice)
}

Slice Tricks dan Best Practices

gofunc sliceTricks() {
    // 1. Reverse slice
    slice := []int{1, 2, 3, 4, 5}
    for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 {
        slice[i], slice[j] = slice[j], slice[i]
    }
    fmt.Println("Reversed:", slice)
    
    // 2. Remove duplicates
    numbers := []int{1, 2, 2, 3, 3, 3, 4, 5, 5}
    unique := removeDuplicates(numbers)
    fmt.Println("Unique:", unique)
    
    // 3. Filter slice
    all := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    even := filter(all, func(n int) bool { return n%2 == 0 })
    fmt.Println("Even numbers:", even)
    
    // 4. Map transformation
    squared := mapTransform([]int{1, 2, 3, 4, 5}, func(n int) int { return n * n })
    fmt.Println("Squared:", squared)
}

func removeDuplicates(slice []int) []int {
    keys := make(map[int]bool)
    var result []int
    
    for _, item := range slice {
        if !keys[item] {
            keys[item] = true
            result = append(result, item)
        }
    }
    return result
}

func filter(slice []int, predicate func(int) bool) []int {
    var result []int
    for _, item := range slice {
        if predicate(item) {
            result = append(result, item)
        }
    }
    return result
}

func mapTransform(slice []int, transform func(int) int) []int {
    result := make([]int, len(slice))
    for i, item := range slice {
        result[i] = transform(item)
    }
    return result
}

Maps di Go: Key-Value Storage yang Efisien

Apa itu Map?

Map adalah struktur data yang menyimpan pasangan key-value. Map di Go mirip dengan hash table atau dictionary di bahasa lain, namun dengan type safety yang ketat.

Deklarasi dan Inisialisasi Map

gofunc mapBasics() {
    // 1. Deklarasi map kosong
    var ages map[string]int
    fmt.Println("Nil map:", ages == nil) // Output: true
    
    // 2. Inisialisasi dengan make
    ages = make(map[string]int)
    ages["Alice"] = 25
    ages["Bob"] = 30
    fmt.Println("Ages map:", ages)
    
    // 3. Map literal
    scores := map[string]int{
        "Math":    95,
        "Science": 87,
        "English": 92,
    }
    fmt.Println("Scores:", scores)
    
    // 4. Map dengan berbagai tipe key
    complexMap := map[int]string{
        1: "One",
        2: "Two",
        3: "Three",
    }
    fmt.Println("Complex map:", complexMap)
}

Operasi Dasar Map

gofunc mapOperations() {
    students := make(map[string]int)
    
    // Menambah elemen
    students["Alice"] = 85
    students["Bob"] = 92
    students["Charlie"] = 78
    
    fmt.Println("Students:", students)
    
    // Mengakses elemen
    aliceScore := students["Alice"]
    fmt.Println("Alice's score:", aliceScore)
    
    // Check if key exists
    score, exists := students["David"]
    if exists {
        fmt.Println("David's score:", score)
    } else {
        fmt.Println("David not found")
    }
    
    // Mengubah nilai
    students["Alice"] = 90
    fmt.Println("Updated Alice's score:", students["Alice"])
    
    // Menghapus elemen
    delete(students, "Charlie")
    fmt.Println("After deletion:", students)
    
    // Iterasi map
    fmt.Println("All students:")
    for name, score := range students {
        fmt.Printf("%s: %d\n", name, score)
    }
}

Map dengan Struct Values

gotype Person struct {
    Name  string
    Age   int
    Email string
}

func mapWithStructs() {
    // Map dengan struct sebagai value
    employees := map[int]Person{
        1001: {Name: "Alice", Age: 30, Email: "alice@company.com"},
        1002: {Name: "Bob", Age: 25, Email: "bob@company.com"},
        1003: {Name: "Charlie", Age: 35, Email: "charlie@company.com"},
    }
    
    fmt.Println("Employees:")
    for id, person := range employees {
        fmt.Printf("ID: %d, Name: %s, Age: %d\n", id, person.Name, person.Age)
    }
    
    // Update struct field
    emp := employees[1001]
    emp.Age = 31
    employees[1001] = emp // Harus assign kembali karena struct is value type
    
    fmt.Println("Updated Alice's age:", employees[1001].Age)
}

Map dengan Pointer Values

gofunc mapWithPointers() {
    // Map dengan pointer ke struct
    employees := make(map[int]*Person)
    
    employees[1001] = &Person{Name: "Alice", Age: 30, Email: "alice@company.com"}
    employees[1002] = &Person{Name: "Bob", Age: 25, Email: "bob@company.com"}
    
    // Update melalui pointer - lebih efisien
    employees[1001].Age = 31
    fmt.Println("Alice's updated age:", employees[1001].Age)
    
    // Check nil pointer
    if emp := employees[1003]; emp != nil {
        fmt.Println("Employee 1003:", emp.Name)
    } else {
        fmt.Println("Employee 1003 not found")
    }
}

Perbandingan: Arrays vs Slices vs Maps

Kapan Menggunakan Array?

gofunc whenToUseArrays() {
    // 1. Ukuran data tetap dan diketahui
    daysInWeek := [7]string{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}
    
    // 2. Performance critical code
    var buffer [1024]byte // Fixed-size buffer
    
    // 3. Matrix operations
    var matrix [3][3]float64
    
    fmt.Println("Days:", daysInWeek)
    fmt.Println("Buffer size:", len(buffer))
    fmt.Println("Matrix dimensions:", len(matrix), "x", len(matrix[0]))
}

Kapan Menggunakan Slice?

gofunc whenToUseSlices() {
    // 1. Dynamic data - ukuran berubah-ubah
    var dynamicList []string
    dynamicList = append(dynamicList, "item1", "item2")
    
    // 2. Function parameters - lebih fleksibel
    processItems([]int{1, 2, 3, 4, 5})
    
    // 3. Sebagai result dari function
    result := generateNumbers(10)
    fmt.Println("Generated:", result)
    
    // 4. Working dengan unknown size
    lines := readLinesFromFile("example.txt") // Returns []string
    fmt.Println("Lines count:", len(lines))
}

func processItems(items []int) {
    for _, item := range items {
        fmt.Printf("%d ", item)
    }
    fmt.Println()
}

func generateNumbers(n int) []int {
    result := make([]int, n)
    for i := 0; i < n; i++ {
        result[i] = i + 1
    }
    return result
}

func readLinesFromFile(filename string) []string {
    // Simulasi reading file
    return []string{"line1", "line2", "line3"}
}

Kapan Menggunakan Map?

gofunc whenToUseMaps() {
    // 1. Key-value relationships
    userRoles := map[string]string{
        "alice":   "admin",
        "bob":     "user",
        "charlie": "moderator",
    }
    
    // 2. Caching/Memoization
    cache := make(map[string]interface{})
    cache["user:123"] = Person{Name: "Alice", Age: 30}
    
    // 3. Counting/Frequency
    wordCount := countWords("hello world hello go world")
    fmt.Println("Word count:", wordCount)
    
    // 4. Fast lookups
    validIDs := map[int]bool{
        1001: true,
        1002: true,
        1003: true,
    }
    
    if validIDs[1001] {
        fmt.Println("ID 1001 is valid")
    }
}

func countWords(text string) map[string]int {
    words := []string{"hello", "world", "hello", "go", "world"} // Simplified
    count := make(map[string]int)
    
    for _, word := range words {
        count[word]++
    }
    
    return count
}

Kesimpulan

Struktur data collection di Go – Arrays, Slices, dan Maps – masing-masing memiliki keunggulan dan use case yang spesifik:

Arrays

  • Keunggulan: Performance optimal, memory layout predictable, type safe
  • Kapan digunakan: Data dengan ukuran tetap, buffer, matrix operations
  • Perhatian: Ukuran adalah bagian dari tipe, tidak fleksibel

Slices

  • Keunggulan: Fleksibel, dynamic sizing, powerful built-in functions
  • Kapan digunakan: Data collection yang berubah-ubah, function parameters, API responses
  • Perhatian: Growth strategy, memory leaks pada large slices

Maps

  • Keunggulan: Fast lookup O(1), key-value relationship, flexible key types
  • Kapan digunakan: Caching, counting, fast lookups, configuration
  • Perhatian: Iteration order tidak guaranteed, nil map panic, memory overhead

Selanjutnya kita akan masuk ke Intermediate Topics.

Seri Belajar Golang – Pemula

  1. Pengenalan Golang: Mengapa Google Menciptakan Bahasa Ini?
  2. Setup Environment dan Hello World di Go
  3. Sintaks Dasar Go: Variables, Constants, dan Data Types
  4. Control Flow di Go: If, Switch, dan Loops
  5. Functions di Go: Parameter, Return Values, dan Named Returns
  6. Arrays, Slices, dan Maps: Struktur Data Penting di Go

3 tanggapan pada “Arrays, Slices, dan Maps: Struktur Data Penting di Go – Pengelolaan Data Collection”

  1. Pingback: Control Flow di Go: If, Switch, dan Loops - Panduan Lengkap Struktur Kontrol

  2. Pingback: Sintaks Dasar Go: Variables, Constants, dan Data Types - Panduan Lengkap

  3. Pingback: Cara Install Golang dan Membuat Program Hello World Pertama

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *