Tony asked for leave these two days, so he asked his good friend Kevin to take charge of the class. The styles of these two people are really far from each other.

Tony is slow in character and gentle in technique. How light is it? I wondered if he was afraid of getting my hair wet while washing it.

Kevin was totally different. He had a big, hot voice. It was hair washing, but I felt like he was slapping me in the head. There was so much water and mist that I could see a rainbow.

It’s a little bit of an exaggeration.

After the study of the last article, I should be more and more comfortable with Go. Today, I will do something more advanced: complex data types.

This article mainly introduces array and slice, open integer ~

All code in this article is written based on go1.16.6.

An array of

Arrays have two characteristics:

  1. Fixed length
  2. Same element type

Because of its fixed length, less is used in the development process than slicing. But arrays are the foundation of slicing, and once you understand arrays, it’s much easier to learn slicing.

Declaration and initialization

Declare an array of length 3 and element type int. The elements of an array are accessed by an index ranging from 0 to the length of the array minus 1. Len is the built-in function that gets the length of the array.

var a [3]int
// Outputs the first element of the array
fmt.Println(a[0]) / / 0
// Outputs the array length
fmt.Println(len(a)) / / 3
Copy the code

An array initializes with an element type of zero. You can also initialize an array with an array literal.

// Array literals are initialized
var b [3]int = [3]int{1.2.3}
var c [3]int = [3]int{1.2}
fmt.Println(b)    / / [1 2 3]
fmt.Println(c[2]) / / 0
Copy the code

If the specified array length is not displayed, use… , the array length is determined by the actual number of elements.

/ / use...
d := [...]int{1.2.3.4.5}
fmt.Printf("%T\n", d) // [5]int
Copy the code

You can also specify the index position to initialize, or if no array length is specified, the length is determined by the index.

// specify index location initialization
e := [4]int{5.2: 10}
f := [...]int{2.4: 6}
fmt.Println(e) // [5 0 10 0]
fmt.Println(f) // [2 0 0 0 6]
Copy the code

Multidimensional array

The first dimension of a multidimensional array is only allowed to use… .

// A two-dimensional array
var g [4] [2]int
h := [4] [2]int{{10.11}, {20.21}, {30.31}, {40.41}}
// Declare and initialize the elements with indexes 1 and 3 in the outer array
i := [4] [2]int{1: {20.21}, 3: {40.41}}
// Declare and initialize the outer array and the inner array's individual elementsj := [...] [2]int{1: {0: 20}, 3: {1: 41}}
fmt.Println(g, h, i, j)
Copy the code

Use an array

An array is comparable as long as its elements are comparable, and its length is part of its type.

So [3]int and [4]int are two different types.

// Array comparison
a1 := [2]int{1.2}
a2 := [...]int{1.2}
a3 := [2]int{1.3}
// a4 := [3]int{1, 2}
fmt.Println(a1 == a2, a1 == a3, a2 == a3) // true false false
// fmt.Println(a1 == a4) // invalid operation: a1 == a4 (mismatched types [2]int and [3]int)
Copy the code

Array traversal:

// Array traversal
for i, n := range e {
	fmt.Println(i, n)
}
Copy the code

Value types

The Go array is a value type, and assignments and arguments copy the entire array.

As you can see from the output, the content is the same, but the address is different.

package main

import "fmt"

func main(a) {
	// Array copy
	x := [2]int{10.20}
	y := x
	fmt.Printf("x: %p, %v\n", &x, x) // x: 0xc00012e020, [10 20]
	fmt.Printf("y: %p, %v\n", &y, y) // y: 0xc00012e030, [10 20]
	test(x)
}

func test(a [2]int) {
	fmt.Printf("a: %p, %v\n", &a, a) // a: 0xc00012e060, [10 20]
}
Copy the code

Let’s look at the function passing parameters:

package main

import "fmt"

func main(a) {
	x := [2]int{10.20}

	/ / the refs
	modify(x)
	fmt.Println("main: ", x) // main: [10 20]
}

func modify(a [2]int) {
	a[0] = 30
	fmt.Println("modify: ", a) // modify: [30 20]
}
Copy the code

As can be seen from the result, after the array content in modify is modified, the array content in main does not change.

So, is it possible to make changes inside the function that affect things outside the function? The answer is yes, and the next section will do it.

Slice slice

Slice is a reference type that has three properties: pointer, length, and capacity.

  1. Pointer: Points to the first element that slice can access.
  2. Length: number of elements in slice.
  3. Capacity: The number of elements between the start of slice and the last element of the underlying array.

Are you confused when you see such an explanation? Don’t panic. Let’s explain it in detail.

Its underlying structure looks like this:

Let’s look at another example to see what all the parts mean.

At the bottom is an array of 10 integer elements, data1 points to the fourth element of the array, length 3, and capacity up to the last element of the array, 7. Data2 refers to the fifth element of the array, with length 4 and capacity 6.

Create a slice

There are two ways to create slices:

The first method is array-based creation:

// Create slices based on arrays
var array = [...]int{1.2.3.4.5.6.7.8}

s1 := array[3:6]
s2 := array[:5]
s3 := array[4:]
s4 := array[:]

fmt.Printf("s1: %v\n", s1) // s1: [4 5 6]
fmt.Printf("s2: %v\n", s2) // s2: [1 2 3 4 5]
fmt.Printf("s3: %v\n", s3) // s3: [5 6 7 8]
fmt.Printf("s4: %v\n", s4) // s4: [1 2 3 4 5 6 7 8]
Copy the code

The second way is to create it using the built-in function make:

// Use make to create slices
// len: 10, cap: 10
a := make([]int.10)
// len: 10, cap: 15
b := make([]int.10.15)

fmt.Printf("a: %v, len: %d, cap: %d\n", a, len(a), cap(a))
fmt.Printf("b: %v, len: %d, cap: %d\n", b, len(b), cap(b))
Copy the code

Using slice

traverse

And traversal number group method is the same.

// slice traversal
for i, n := range s1 {
	fmt.Println(i, n)
}
Copy the code

To compare

You can’t use == to test if two slices have the same element, but slice can be compared to nil. The zero value for slice is nil, which means there is no corresponding underlying array, and the length and capacity are zero.

But also note that both length and capacity are zero, and the value is not necessarily nil.

/ / to compare
var s []int
fmt.Println(len(s) == 0, s == nil) // true true
s = nil
fmt.Println(len(s) == 0, s == nil) // true true
s = []int(nil)
fmt.Println(len(s) == 0, s == nil) // true true
s = []int{}
fmt.Println(len(s) == 0, s == nil) // true false
Copy the code

So, to determine whether slice is empty, use the built-in function len, not whether it is nil.

Additional elements

Use the built-in function Append.

/ / append
s5 := append(s4, 9)
fmt.Printf("s5: %v\n", s5) // s5: [1 2 3 4 5 6 7 8 9]
s6 := append(s4, 10.11)
fmt.Printf("s6: %v\n", s6) // s5: [1 2 3 4 5 6 7 8 10 11]
Copy the code

Append another slice to be followed by three dots.

// Append another slice
s7 := []int{12.13}
s7 = append(s7, s6...)
fmt.Printf("s7: %v\n", s7) // s7: [12 13 1 2 3 4 5 6 7 8 10 11]
Copy the code

copy

Use the built-in function copy.

/ / copy
s8 := []int{1.2.3.4.5}
s9 := []int{5.4.3}
s10 := []int{6}

copy(s8, s9)
fmt.Printf("s8: %v\n", s8) // s8: [5 4 3 4 5]
copy(s10, s9)
fmt.Printf("s10: %v\n", s10) // s10: [5]
Copy the code

Reference types

As we mentioned in the previous section, arrays are value types, so the entire array is copied when passing parameters. If the array is large, it can affect performance. Passing slices only copies the slices themselves and does not affect the underlying array, which is very efficient.

package main

import "fmt"

func main(a) {
	s9 := []int{5.4.3}

	/ / the refs
	modify(s9)
	fmt.Println("main: ", s9) // main: [30 4 3]
}

func modify(a []int) {
	a[0] = 30
	fmt.Println("modify: ", a) // modify: [30 4 3]
}

Copy the code

Values changed in modify will affect main.

conclusion

This article looked at the first two types of composite data types: arrays and slicing. It introduces their creation, common operations, and passing between functions.

Array length is fixed, is the basis of slicing; Slice length variable, more than a capacity attribute, its pointer to the underlying structure is an array.

In the function parameter passing process, if the array is very large, it will affect the efficiency, and slicing solves this problem, and the efficiency is higher.

In daily development, slicing is used more often.


The brain map and source code in the article have been uploaded to GitHub for students who need to download.

Address: github.com/yongxinz/go…

List of Go columns:

  1. Development environment setup and development tools VS Code configuration

  2. Declaration and assignment of variables and constants

  3. Basic data types: integer, floating point, complex, Boolean, and string