What is an array
An array is a collection of elements of the same type. For example, a collection of integers 5, 8, 9, 79, 76 forms an array. There is no allow mixing of different types of values in Go, for example, arrays containing both strings and integers.
Declare an array
Arrays belong to type. Represents the number of elements in the array and represents the type of each element. The number of elements is also part of the type (we will discuss this in more detail later.[n]TnTn
There are different ways to declare an array. Let's take a look one by one.
package main import ( "fmt" ) func main() { var a [3]int //int array with length 3 (a) }
var a [3]int Declares an array of integers of length 3. All elements in the array will automatically assign zero values of the array type. In this case it is an array of integers, so all elements are assigned to the zero value of int. Run the above program to printa a 0
[0 0 0]
The index of the array starts from , and ends at . Let's assign some values to the above array. 0 length - 1.
package main import ( "fmt" ) func main() { var a [3]int //int array with length 3 a[0] = 12 // array index starts at 0 a[1] = 78 a[2] = 50 (a) }
a[0] Assigns the value to the first element of the array. The program will print
[12 78 50]
Let's create the same array using the phrase syntax declaration.
package main import ( "fmt" ) func main() { // short hand declaration to create array a := [3]int{12, 78, 50} (a) }
The above program will print the same output:
[12 78 50]
During a phrase syntax declaration, it is not necessary to assign values to all elements in the array.
package main import ( "fmt" ) func main() { a := [3]int{12} (a) }
In the above program, line 8 declares an array of length 3, but only provides one value. The remaining 2 elements will be automatically specified. This program will printa := [3]int{12} 12 0
[12 0 0]
You can even ignore the length of the array in the declaration and replace it with and let the compiler find the length for you. This is done in the following program....
package main import ( "fmt" ) func main() { // ... makes the compiler determine the length a := [...]int{12, 78, 50} (a) }
The size of the array is part of the type. Therefore and are different types. Therefore, it is impossible to resize the array.
package main func main() { a := [3]int{5, 78, 8} var b [5]int b = a //not possible since [3]int and [5]int are distinct types }
In line 6 of the program above, we try to assign a variable of type to an unsubmitted type variable, so the compiler will print the following error:
./:6:7: cannot use a (type [3]int) as type [5]int in assignment
Array is a value type
Arrays in Go are value types, not reference types. This means that when they are assigned to new variables, a copy of the original array will be assigned to the new variable. If a new variable is changed, it will not be reflected in the original array.
package main import "fmt" func main() { a := [...]string{"USA", "China", "India", "Germany", "France"} b := a // a copy of a is assigned to b b[0] = "Singapore" ("a is ", a) ("b is ", b) }
The above code will print out the following:
a is [USA China India Germany France]
b is [Singapore China India Germany France]
Likewise, when arrays are passed as arguments to functions, they are passed by values, and the original array remains the same.
package main import "fmt" func changeLocal(num [5]int) { num[0] = 55 ("inside function ", num) } func main() { num := [...]int{5, 6, 7, 8, 8} ("before passing to function ", num) changeLocal(num) //num is passed by value ("after passing to function ", num) }
In the 13th line program above, the array is actually passed to the function by value, so it will not change due to function calls. The program will print:
before passing to function [5 6 7 8 8]
inside function [55 6 7 8 8]
after passing to function [5 6 7 8 8]
The length of the array
Find the length of the array by passing it as an argument to the function (len).
package main import "fmt" func main() { a := [...]float64{67.7, 89.8, 21, 78} ("length of a is",len(a)) }
The above program will print:
length of a is 4
Iterate the array
Use for to iterate over elements of an array.
package main import "fmt" func main() { a := [...]float64{67.7, 89.8, 21, 78} for i := 0; i < len(a); i++ { //looping from 0 to the length of the array ("%d th element of a is %.2f\n", i, a[i]) } }
The above program uses a loop to iterate over elements of an array, from index to . The program is valid and will print:
0 th element of a is 67.70
1 th element of a is 89.80
2 th element of a is 21.00
3 th element of a is 78.00
Go provides a better and cleaner way to iterate over arrays by using the range form of loops. Returns the index and the value at that index. Let's rewrite the above code using scope. We will also find the sum of all the elements in the array.
package main import "fmt" func main() { a := [...]float64{67.7, 89.8, 21, 78} sum := float64(0) for i, v := range a {//range returns both the index and value ("%d the element of a is %.2f\n", i, v) sum += v } ("\nsum of all elements of a",sum) }
Line 8 of the above program is the scope form of the for loop. It will return the index and the value at that index. We print the values and calculate the sum of all elements in the array. The output of this program is:
0 the element of a is 67.70
1 the element of a is 89.80
2 the element of a is 21.00
3 the element of a is 78.00
sum of all elements of a 256.5
If you want only the value and want to ignore the index, you can do this by replacing the index with a blank identifier._
for _, v := range a { //ignores index }
The for loop above ignores the index. Similarly, this value can be ignored.
Multidimensional array
So far, the arrays we have created are all single-dimensional. Multidimensional arrays can be created.
package main import ( "fmt" ) func printarray(a [3][2]string) { for _, v1 := range a { for _, v2 := range v1 { ("%s ", v2) } ("\n") } } func main() { a := [3][2]string{ {"lion", "tiger"}, {"cat", "dog"}, {"pigeon", "peacock"}, //this comma is necessary. The compiler will complain if you omit this comma } printarray(a) var b [3][2]string b[0][0] = "apple" b[0][1] = "samsung" b[1][0] = "microsoft" b[1][1] = "google" b[2][0] = "AT&T" b[2][1] = "T-Mobile" ("\n") printarray(b) }
In line 17 of the program above, a two-dimensional array of strings is declared using short-sign syntax. A comma at the end of line 20 is required. This is because the lexer automatically inserts semicolons based on simple rules. Another 2d array is declared in line 23 and adds strings one by one for each index. This is another way to initialize a 2d array.
The function in line 7 uses two for range loops to print the contents of the 2d array. The above program will print:
lion tiger
cat dog
pigeon peacock
apple samsung
microsoft google
AT&T T-Mobile
That's it for arrays. Although arrays seem to be flexible enough, they have fixed length limitations. The length of the array cannot be increased. This is where the slice enters the screen. In fact, in Go, slices are more common than traditional arrays.
slice
Slicing is a convenient, flexible and powerful wrapper on top of an array. The slice itself does not own any data. They are just references to existing arrays.
Create slices
Slices with T-type elements are represented by the following formula[]T
。
package main import ( "fmt" ) func main() { a := [5]int{76, 77, 78, 79, 80} var b []int = a[1:4] //creates a slice from a[1] to a[3] (b) }
This syntax creates a slice from one index to another starting from an array. Therefore, in line 9 of the above program, create a slice representation of the array from index 1 to 3. Use this expression:a[start:end]
。
package main import ( "fmt" ) func main() { //creates and array and returns a slice reference c := []int{6, 7, 8} (c) }
In line 9 of the function above, create an array of 3 integers and return the slice reference stored in c.
Modify slices
The slice does not own any data. It is just a representation of the underlying array. Any modifications made to the slice will be reflected in the underlying array.
package main import ( "fmt" ) func main() { darr := [...]int{57, 89, 90, 82, 100, 78, 67, 69, 59} dslice := darr[2:5] ("array before",darr) for i := range dslice { dslice[i]++ } ("array after",darr) }
In line 9 of the above program, we create from the index 2, 3, 4 of the array. The for loop increments the values in these indexes by 1. When we print the array after the for loop, we can see that the changes to the slice are reflected in the array. The output of the program is:
array before [57 89 90 82 100 78 67 69 59]
array after [57 89 91 83 101 78 67 69 59]
When multiple slices share the same underlying array, changes made by each slice are reflected in the array.
package main import ( "fmt" ) func main() { numa := [3]int{78, 79 ,80} nums1 := numa[:] //creates a slice which contains all elements of the array nums2 := numa[:] ("array before change 1",numa) nums1[0] = 100 ("array after modification to slice nums1", numa) nums2[1] = 101 ("array after modification to slice nums2", numa) }
In line 9, the start and end values are missing. The default values for "start" and "end" are and , respectively. Two slices and share the same array. The output of the program is:
array before change 1 [78 79 80]
array after modification to slice nums1 [100 79 80]
array after modification to slice nums2 [100 101 80]
It is clear from the output that when the slices share the same array. Modifications made to slices will be reflected in the array.
Slice length and capacity
The length of the slice is the number of elements in the slice. The capacity of a slice is the number of elements in the underlying array starting from the index that creates the slice.
package main import ( "fmt" ) func main() { fruitarray := [...]string{"apple", "orange", "grape", "mango", "water melon", "pine apple", "chikoo"} fruitslice := fruitarray[1:3] ("length of slice %d capacity %d", len(fruitslice), cap(fruitslice)) //length of fruitslice is 2 and capacity is 6 }
In the above program, it is created from indexes 1 and 2 of . Therefore, the length is 2.
The slice can be resliced to its capacity. Anything beyond this value will cause the program to throw a runtime error.
package main import ( "fmt" ) func main() { fruitarray := [...]string{"apple", "orange", "grape", "mango", "water melon", "pine apple", "chikoo"} fruitslice := fruitarray[1:3] ("length of slice %d capacity %d\n", len(fruitslice), cap(fruitslice)) //length of is 2 and capacity is 6 fruitslice = fruitslice[:cap(fruitslice)] //re-slicing furitslice till its capacity ("After re-slicing length is",len(fruitslice), "and capacity is",cap(fruitslice)) }
In line 11 of the above program, it is resliced to its capacity. The above program output:
length of slice 2 capacity 6
After re-slicing length is 6 and capacity is 6
Create slices with make
To generate slices, make([]T, len, cap) can be used to create slices. []T represents the data type, len represents the slice length, and cap represents the slice capacity. The make function creates an array and returns a slice reference to it.
package main import ( "fmt" ) func main() { i := make([]int, 5, 5) (i) }
By default, these values are cleared when creating slices with make. The above program will output .[0 0 0 0 0]
Slice append
As we already know, arrays are limited to fixed lengths and their length cannot be increased. Slices are dynamic, and new elements can be appended to slices using functions. The definition of append function is .append([]T, x...):[]T
. Returns a new slice.
x ...T in the function definition indicates that the function accepts a variable number of parameters of the parameter x. These types of functions are calledVariable parameter functions。
However, there is one problem that may bother you. If the slice is supported by an array, and the array itself has a fixed length, how can the slice have a dynamic length. What happens under the hood is that when a new element is appended to the slice, a new array is created. Elements of an existing array are copied to this new array and return a new slice reference to this new array. The new slice is now twice as powerful as the old slice. The following program will make things clear.
package main import ( "fmt" ) func main() { cars := []string{"Ferrari", "Honda", "Ford"} ("cars:", cars, "has old length", len(cars), "and capacity", cap(cars)) //capacity of cars is 3 cars = append(cars, "Toyota") ("cars:", cars, "has new length", len(cars), "and capacity", cap(cars)) //capacity of cars is doubled to 6 }
In the above program, the capacity is initially 3. We attach the new element to the car in line 10 and assign the returned slice to the car again. Now, the capacity of the car has doubled to become 6 vehicles. The output of the above program is:
cars: [Ferrari Honda Ford] has old length 3 and capacity 3
cars: [Ferrari Honda Ford Toyota] has new length 4 and capacity 6
The zero value of slice type is . The length and capacity of the slice are 0. You can use the append function to append values to slices.
package main import ( "fmt" ) func main() { var names []string //zero value of a slice is nil if names == nil { ("slice is nil going to append") names = append(names, "John", "Sebastian", "Vinay") ("names contents:",names) } }
In the above program as nil, we have appended 3 strings to . The output of the program is:
slice is nil going to append
names contents: [John Sebastian Vinay]
You can also use operators to append a slice to another slice.
package main import ( "fmt" ) func main() { veggies := []string{"potatoes","tomatoes","brinjal"} fruits := []string{"oranges","apples"} food := append(veggies, fruits...) ("food:",food) }
In line 10 of the above program, by appending to the slice. The output of the program is:
fruitsveggiesfood: [potatoes tomatoes brinjal oranges apples]
Slice as function parameter
Slices can be treated as represented internally by structure types.
type slice struct { Length int Capacity int ZerothElement *byte }
A slice contains length, capacity, and a pointer to the zeroth element of the array. When passing a slice to a function, the pointer variable will reference the same underlying array even if it is passed by value. Therefore, when a slice is passed to a function as an argument, the changes made inside the function are also visible outside the function. Let's write a program to check it out.
package main import ( "fmt" ) func subtactOne(numbers []int) { for i := range numbers { numbers[i] -= 2 } } func main() { nos := []int{8, 7, 6} ("slice before function call", nos) subtactOne(nos) //function modifies the slice ("slice after function call", nos) //modifications are visible outside }
The function call in line 17 of the above program decrements each element of the slice by 2. These changes are visible when printing slices after function calls. If you remember, this is different from an array, where changes made to arrays inside a function are not visible outside of the function. The output of the above program is
slice before function call [8 7 6]
slice after function call [6 5 4]
Multidimensional slices
Similar to arrays, slices can have multiple dimensions.
package main import ( "fmt" ) func main() { pls := [][]string { {"C", "C++"}, {"JavaScript"}, {"Go", "Rust"}, } for _, v1 := range pls { for _, v2 := range v1 { ("%s ", v2) } ("\n") } }
The output result is:
C C++
JavaScript
Go Rust
Slices save references to the underlying array. As long as the slice is in memory, the array cannot be garbage collected. In terms of memory management, this may attract attention. Let's assume we have a very large array and we're only interested in dealing with a small portion of it. From then on, we create a slice from that array and start processing that slice. The important thing to note here is that the array will still be in memory because the slice references it.
One way to solve this problem is to use the copy function to copy the slice. This way we can use new slices and we can garbage collect the original array.copy(dst, src []T):int
。
package main import ( "fmt" ) func countries() []string { countries := []string{"USA", "Singapore", "Germany", "India", "Australia"} neededCountries := countries[:len(countries)-2] countriesCpy := make([]string, len(neededCountries)) copy(countriesCpy, neededCountries) //copies neededCountries to countriesCpy return countriesCpy } func main() { countriesNeeded := countries() (countriesNeeded) }
In line 9 of the above program, create a slice that prohibits the last 2 elements. Line 11 of the above program is copied to the function in the next line and returns it from it. The array can now be garbage collected because it is no longer referenced.
The above is a detailed article about how to quickly learn Go slices and array data types. For more information about Go slices, please pay attention to my other related articles!