Arrays vs Slices
image from wikedia

Arrays vs Slices

With this article I have tried giving a brief overview of two fundamental data structures in the Go programming language: arrays and slices. This may help anyone coming from a dynamic language to Go and understand the basics of couple of most used data structures in all programs .

Arrays

Arrays are fundamental data structures in the Go programming language that allow you to store and manage collections of elements of the same type. An array is a fixed-size sequence that holds a contiguous block of memory, where each element can be accessed using its index. Arrays provide an efficient way to store and manipulate data when you know the exact number of elements you need to manage.

In Go, arrays are inherently homogeneous, meaning they can only hold elements of the same data type.

For example, you can declare an array of integers as follows:

numbers := [5]int{10, 20, 30, 40, 50}
strings:= [5]string {"jupiter", "Pluto", "Mars", "Saturn", "Venus"}
        

Slices

Slices in Go are similar to JavaScript's arrays or Python's lists. Unlike arrays, which have fixed sizes, slices allow for the creation of sequences that can grow or shrink as needed. This adaptability is particularly valuable when dealing with variable-length data sets or scenarios where the exact number of elements is uncertain, making slices more commonly used than arrays directly.

Here is an example of creating slices in Go:

numbers := []int{10, 20, 30, 40, 50}
strings := []string{"jupiter", "Pluto", "Mars", "Saturn", "Venus"}
        

Notice how we do not declare a size for slices as we do with arrays.In Go, slices are usually homogeneous, meaning they only contain elements of the same type. However, you can achieve heterogeneity by using a slice of empty interfaces, denoted as []interface{}.

For example, you can create a heterogeneous slice like this:

heterogeneousSlice := []interface{}{
    42,           // int
    "Hello",      // string
    3.14,         // float64
    true,         // bool
    []int{1, 2},  // slice of int
    map[string]int{"a": 1, "b": 2}, // map
}
        

Underlying Arrays of Slices

The underlying array of slices refers to how slices are implemented in Go. When a slice is created, it doesn't store the data directly. Instead, it contains a reference to an underlying array, and it keeps track of where its portion of that array begins and ends.

Think of the underlying array as a large storage area. When you create a slice, you're essentially defining a subset of that storage area. The slice's start and end positions in the underlying array are determined by the index you provide when you create the slice. This array is not directly accessible, as we have not declared and initialized it ourselves, but it is created when we create a slice. Of course, we can always create a slice out of an array we declared.

// Declare an array of integers
numbers := [5]int{10, 20, 30, 40, 50}
// Create slices from the array
slice := numbers[1:4]
        

One significant difference between arrays and slices is that we cannot compare slices directly using the == operator. While arrays are values, slices are references to underlying arrays. Therefore, comparing slices using == would compare the references, not the contents. If you need to compare the contents of slices, you must loop through the elements and compare them individually.

Cap vs Len The built-in make function is a convenient tool for creating slices. By specifying the type and capacity, a new slice is initialized and ready to be populated with elements.

b := make([]int, 0, 5) // len(b)=0, cap(b)=5

b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:]      // len(b)=4, cap(b)=4        

If you notice, make takes three arguments - type, length, and capacity, where the last argument (capacity) is optional. Let's discuss how capacity is different from the length of a slice.

A slice is an abstraction that uses an array underneath.

cap tells you the capacity of the underlying array, while len tells you how many items are in the array.

The slice abstraction in Go is very nice because it resizes the underlying array for you. Since arrays in Go cannot be resized, slices are almost always used instead.

Example:

s := make([]int, 0, 3)
for i := 0; i < 5; i++ {
    s = append(s, i)
    fmt.Printf("cap %v, len %v, %p\\n", cap(s), len(s), s)
}
        

Will output something like this:

cap 3, len 1, 0x1040e130
cap 3, len 2, 0x1040e130
cap 3, len 3, 0x1040e130
cap 6, len 4, 0x10432220
cap 6, len 5, 0x10432220
        

In conclusion, arrays and slices are both essential data structures in Go that allow you to store and manage collections of elements. Arrays provide an efficient way to store and manipulate data when you know the exact number of elements you need to manage, while slices are more flexible and adaptable when dealing with variable-length data sets. Understanding the differences between these data structures is crucial to write efficient, maintainable Go code.

要查看或添加评论,请登录

Shashank Shekhar的更多文章

  • Chat server with Websocket in Node JS

    Chat server with Websocket in Node JS

    WebSockets are powerful tools for real-time communication, allowing clients and servers to maintain an open connection…

    1 条评论
  • Async IO programming with Node js

    Async IO programming with Node js

    Introduction Asynchronous programming is a technique that enables your program to start a potentially long-running task…

  • Typescript Programming Guide

    Typescript Programming Guide

    Introduction By now, TypeScript has emerged as a fully-fledged de facto standard for writing secure, enterprise-grade…

  • Error as values and Return Types in Go

    Error as values and Return Types in Go

    Error Handling in Go is bit different than traditional way you must have seen in programming in languages like…

    2 条评论
  • Maps, Structs and More.

    Maps, Structs and More.

    While arrays and slices form the core of sequential data structures, maps, interfaces, and structs offer unique…

  • Pointers in Go

    Pointers in Go

    In Go, a pointer is a variable that stores the memory address of another variable. We use the ampersand (&) operator to…

  • Understanding the Distinctions: never vs void

    Understanding the Distinctions: never vs void

    In TypeScript, the never and void types serve distinct purposes, despite their similarities in indicating absence of…

    1 条评论
  • Developing Good Coding Habits with AI-Powered Code Reviews

    Developing Good Coding Habits with AI-Powered Code Reviews

    As developers, we are always looking to improve our coding skills and write better code. One way to achieve this is by…

  • Microsoft Graph

    Microsoft Graph

    For past couple of weeks I have been working with Microsoft Graph API to consume few of Microsoft services. I was…

社区洞察

其他会员也浏览了