- The original address: www.sohamkamani.com/blog/golang…
- By Soham Kamani
- Translation address: github.com/watermelo/d…
- Translator: Khaki Khaki
- Translator level is limited, if there is translation or understanding fallacy, please help to point out
First, it’s easy to see that arrays and slicing seem to be the same thing: a data structure that represents a list. However, they are actually quite different from each other.
In this article, we will explore their differences and implementations in Go.
An array of
An array is a fixed list of data. The point here is fixed, because once the length of an array is set, it cannot be changed.
Let’s take an example of an array that declares four integers:
arr := [4]int{3.2.5.4}
Copy the code
Length and type
The arR variable we defined in the above example is of type [4] int, which is an array of size 4. It is important to note here that 4 is included in the type definition.
This means that two arrays of different lengths are actually two different types. So you cannot treat arrays of different lengths as one type, nor can you assign the value of one to the other:
longerArr := [5]int{5.7.1.2.0}
longerArr = arr
// a compilation error is thrown
longerArr == arr
// a compilation error is thrown
Copy the code
I’ve found that a good way to think about arrays is structures. If we could construct an array equivalent structure, it might look something like this:
// The equivalent structure of an array of length 4
type int4 struct {
e0 int
e1 int
e2 int
e3 int
}
// The equivalent structure of an array of length 5
type int5 struct {
e0 int
e1 int
e2 int
e3 int
e5 int
}
arr := int4{3.2.5.4}
longerArr := int5{5.7.1.2.0}
Copy the code
This is not recommended, but it is a good way to see why arrays of different lengths are completely different types.
Memory said
Array stores a sequence of n blocks of the specified type:
This memory is allocated immediately after a variable of array type is initialized.
reference
In Go, there is no reference passing. Everything is passed by value. If you assign the value of an array to another variable, the entire value is copied.
If you just want to pass “references” to arrays, you can use Pointers:
In memory allocation and functions, an array is actually a very simple data type that works the same way as a structure.
slice
We can think of slicing as an advanced array-based implementation.
Slicing is implemented in Go to cover some of the very common requirements that developers face when working with lists, such as the need to dynamically resize.
Declaring a slice is almost the same as declaring an array, except that the length must be omitted:
slice := []int{4.5.3}
Copy the code
Just looking at the code, slicing and arrays look very similar, but there are actually significant differences in implementation and use.
Memory said
Slices are allocated differently from arrays and are actually modified Pointers. Each slice contains three pieces of information:
- A pointer to a data sequence
- Length: Indicates the total number of elements currently contained.
- Capacity: The total number of configured memory locations.
Slices of different lengths can then be assigned to each other’s values. They are of the same type, with varying Pointers, length, and capacity:
slice1 := []int{6.1.2}
slice2 := []int{9.3}
// Slices of any length can be allocated to other slices
Copy the code
Unlike arrays, slicing does not allocate memory for chunks of data during initialization. In fact, slices are initialized with nil values.
reference
Slices assigned to another variable are still passed by value. The values here refer only to Pointers, length, and capacity, not to the memory occupied by the element itself. (Here’s an experiment to get a better idea of the process.)
Add new elements
To add elements to slices, you usually use the append function.
nums := []int{8.0}
nums = append(nums, 8)
Copy the code
Internally, this assigns the specified value to the new element and returns a new slice. The length of this new slice has increased by 1. (See Fried Fish and Stefno’s blog for an expanded analysis of slices.)
This is why it is often recommended to create a slice with a pre-specified length and capacity (especially if you have a good idea of what its size might be) :
arr := make([]int.0.5)
// This will create a slice of length 0 and capacity 5
Copy the code
Usage scenarios for arrays and slicing
Arrays and slicing are completely different, and therefore, their use cases are completely different.
Let’s take a look at some examples from open source projects and the Go standard library to see how they are used.
Example 1: UUID
A UUID is 128-bit data that is typically used to uniquely identify an object or entity. Hexadecimal values, usually delimited by hyphens:
e39bdaf4-710d-42ea-a29b-58c368b0c53c
Copy the code
In Google’s UUID library, UUID is represented as a 16-byte array:
type UUID [16]byte
Copy the code
This makes sense because we know that UUID is made up of 128 bits (16 bytes). We don’t add or remove any bytes from the UUID, so it’s better to use an array.
Example 2: Integer sort
In the next example, we’ll look at the sort.ints function in the sorting standard library:
s := []int{5.2.6.3.1.4} // unsorted
sort.Ints(s)
fmt.Println(s)
// [1 2 3 4 5 6]
Copy the code
Sort.ints takes a list of integers and sorts them. I chose slices here for two reasons:
- The number of integers is not specified (any number of integers can be sorted).
- These numbers need to be sorted in place. Using an array passes the entire list of integers as values, so the function only sorts its copies, not the values passed to it. Sort.ints specifies that the input type is slice, because arrays of different lengths are different types.
conclusion
Now that we’ve covered the key differences between arrays and slicing and their use cases, here are some hints for deciding which structure is more appropriate:
- If the entity consists of a set of non-empty items of fixed length: use arrays.
- When you need to add or remove elements from a list, use slicing.
- If the list can contain any number of elements, use slicing.
- Do you modify the list in any way? If so, use slices
As you can see, slicing covers most scenarios for creating applications in Go. Arrays do have their place, though, and are useful when needed.
Do you have a better example? If there are any examples where you prefer slicing over arrays (and vice versa)? Let us know in the comments below 👇