Slices
04/12/21 08:18 Filed in: GO
Today I dive into something called a "slice" in GO. A slice is a collection that can change size to accommodate a changing number of elements. Arrays in GO are fixed to the size they are declared.
Declaring a slice is similar to declaring an array. I can declare an array:
var nums [5]float64
Which specifies a fixed-size array of 5 float64 numbers. If you try to add more than five elements, you will generate an error.
To declare a slice of float64 numbers, I use an empty set of brackets:
var nums []float64
I wonder why this wasn't just called an array. It turns out declaring a slice doesn't give you anything. That is, declaring a slice doesn't allocate memory, whereas declaring the above array allocates enough memory for five numbers. In order for GO to actually set aside memory, you need to call a function cleverly called make and pass in the same type declaration. When using make you need to specify the initial number of elements you want.
var nums []float64
nums = make([]float64,10) // allocates space for 10 float64s
Which is wordy, but you can use a quick declaration:
nums := make([]float64,10) // declare and allocate 10 elements
You can also initialize the slice at the same time: Once created, you assign values to elements as if it is an array (which it is).
nums := []float64, {1,2,3,4,5,6,7,8,9,0}
Because you know the number elements initially, you don't need to use make. [Side note: Having all of these syntactic variations is bizarre and confusing. Why not just have a single simple way for all options.]
Also, a slice that has been declared but has no values (an empty slice) returns nil.
As in other languages, you can use the : operator to get a range of items from the slice. The operator itself is called the "slice operator". For example, assume the above slice:
firstthree := nums[0:3]
Will return [1,2,3]. This is equivalent to Swift's 0..<3 The range does not include the upper limit. One thing about GO slices is that you can get the last 3 elements with:
lastthree := nums[7:10] // returns 8,9,0
Which looks weird since the upper limit (10) doesn't exist as an array element. I like the closed range of Swift's 7…9 better. As in other languages you can omit the lower or upper limit which will default to the first or last element.
Another strange thing is that if you change the base array, you change any slices that use it. That is, if I use the firstthree slice, and I execute:
nums[1] = 7
firstthree will change to reflect it and have a value of: [1,7,3]. The reason is that a slice, such as firstthree, is a pointer to the range in the base array.
Because a slice is not fixed in size, I can add items to a slice using append.
nums = append(nums,12) // add 12 to the end of the base array
nums = append(nums,12,13,14) // add three numbers to the end of the base array.
I should assign the result of the operation back to the same slice, since the base array is copied to a larger array (because the base array can't change size), and the pointer to the base array will change. That is, nums is a reference to the base array.
There is no built-in way to delete elements from a slice. In order to remove an element, I can just use another slice. My lastthree slice above, essentially removes the first 7 elements (but doesn't change the base array). I can append slices to slices if I want to remove elements from the middle.
That's it for today.
Slices
Declaring a slice is similar to declaring an array. I can declare an array:
var nums [5]float64
Which specifies a fixed-size array of 5 float64 numbers. If you try to add more than five elements, you will generate an error.
To declare a slice of float64 numbers, I use an empty set of brackets:
var nums []float64
I wonder why this wasn't just called an array. It turns out declaring a slice doesn't give you anything. That is, declaring a slice doesn't allocate memory, whereas declaring the above array allocates enough memory for five numbers. In order for GO to actually set aside memory, you need to call a function cleverly called make and pass in the same type declaration. When using make you need to specify the initial number of elements you want.
var nums []float64
nums = make([]float64,10) // allocates space for 10 float64s
Which is wordy, but you can use a quick declaration:
nums := make([]float64,10) // declare and allocate 10 elements
You can also initialize the slice at the same time: Once created, you assign values to elements as if it is an array (which it is).
nums := []float64, {1,2,3,4,5,6,7,8,9,0}
Because you know the number elements initially, you don't need to use make. [Side note: Having all of these syntactic variations is bizarre and confusing. Why not just have a single simple way for all options.]
Also, a slice that has been declared but has no values (an empty slice) returns nil.
Slice Operator
As in other languages, you can use the : operator to get a range of items from the slice. The operator itself is called the "slice operator". For example, assume the above slice:
firstthree := nums[0:3]
Will return [1,2,3]. This is equivalent to Swift's 0..<3 The range does not include the upper limit. One thing about GO slices is that you can get the last 3 elements with:
lastthree := nums[7:10] // returns 8,9,0
Which looks weird since the upper limit (10) doesn't exist as an array element. I like the closed range of Swift's 7…9 better. As in other languages you can omit the lower or upper limit which will default to the first or last element.
Another strange thing is that if you change the base array, you change any slices that use it. That is, if I use the firstthree slice, and I execute:
nums[1] = 7
firstthree will change to reflect it and have a value of: [1,7,3]. The reason is that a slice, such as firstthree, is a pointer to the range in the base array.
Appending to a Slice
Because a slice is not fixed in size, I can add items to a slice using append.
nums = append(nums,12) // add 12 to the end of the base array
nums = append(nums,12,13,14) // add three numbers to the end of the base array.
I should assign the result of the operation back to the same slice, since the base array is copied to a larger array (because the base array can't change size), and the pointer to the base array will change. That is, nums is a reference to the base array.
There is no built-in way to delete elements from a slice. In order to remove an element, I can just use another slice. My lastthree slice above, essentially removes the first 7 elements (but doesn't change the base array). I can append slices to slices if I want to remove elements from the middle.
That's it for today.