What’s better about go arrays than slicing?

Time:2022-1-15

Hello, I’m fried fish.

Some time ago, there was a quick news broadcast, that is, go1 17 will officially support the conversion from slice to array. It is no longer necessary to use the previous method, which is much safer.

However, some students have raised new doubts. In go language, arrays are actually used relatively less. Some students even think that arrays can be removed in go.

What's better about go arrays than slicing?

What are the advantages of arrays over slices, and what scenarios should we use them in?

This is a problem that we need to study deeply, so let’s explore it with you today. This article will briefly introduce what arrays and slices are, and then further analyze the use scenarios of arrays.

Happily start the road of sucking fish together.

What is an array

There is a basic data type in go language, which is called array. The format is:[n]T。 Is an array of N values of type T.

The basic declaration format is:

var a [10]int

Represents the declaration of a variable a, which is an array containing 10 integers. The length of an array is part of its type, so the array cannot be resized at will.

For example:

func main() {
 var a [2]string
 A [0] = "brain in"
 A [1] = "fried fish"
 fmt.Println(a[0], a[1])
 fmt.Println(a)

 primes := [6]int{2, 3, 5, 7, 11, 13}
 fmt.Println(primes)
}

Output results:

Fried fish in my head
[Fried fish in my head]
[2 3 5 7 11 13]

In terms of assignment and access, arrays can be operated separately for different indexes. On the memory layout, the indexes 0 and 1 of the array Yes, it will be in the adjacent area and can be accessed directly.

What is the slice

Why do arrays seem to be rarely used in business code. Because the go language has a sliced data type:

The basic declaration format is:

var a []T

Represents that variable a is slice T with type elements. Slice by specifying two indexes (lower and upper) separated by colons:

a[low : high]

For example:

func main() {
 Primes: = [3] string {"fried fish", "do", "go"}

 var s []string = primes[1:3]
 fmt.Println(s)
}

Output results:

[go]

Slicing supports dynamic capacity expansion and contraction, and does not need the attention of the user side, which is very convenient. More importantly, the underlying data structure of the slice itself contains arrays:

type slice struct {
 array unsafe.Pointer
 len   int
 cap   int
}

Many people laugh:In go language, arrays can be laid off. It’s done with slicing

What do you think of this statement? Think quickly about the answer in your heart.

Advantages of arrays

After introducing the basic scenes of arrays and slices, let’s first learn about the official readme on the advantages of arrays:

Arrays are useful when planning the detailed layout of memory and sometimes can help avoid allocation, but primarily they are a building block for slices.

Very crude: arrays are useful when planning the detailed layout of memory. Sometimes they can help avoid allocation, but mainly they are piecemeal building blocks.

Let’s further interpret it to see what the official “ciphertext” specifically refers to. We interpret the ciphertext as the following contents for explanation:

  • Comparable.
  • Compile safe.
  • Length is type.
  • Plan memory layout.
  • Access speed.

Comparable

Arrays are fixed length and can be compared. Arrays are value objects (not reference or pointer types). You will not encounter misjudgment of interface and other comparisons:

func main() {
 A1: = [3] string {"brain", "in", "fried fish"}
 A2: = [3] string {"fried fish", "in", "brain"}
 A3: = [3] string {"brain", "in", "fried fish"}

 fmt.Println(a1 == a2, a1 == a3)
}

Output results:

false true

On the other hand, slices cannot be directly compared or used for judgment:

func main() {
 A1: = [] string {"brain", "in", "fried fish"}
 A2: = [] string {"fried fish", "in", "brain"}
 A3: = [] string {"brain", "in", "fried fish"}

 fmt.Println(a1 == a2, a1 == a3)
}

Output results:

# command-line-arguments
./main.go:10:17: invalid operation: a1 == a2 (slice can only be compared to nil)
./main.go:10:27: invalid operation: a1 == a3 (slice can only be compared to nil)

At the same time, the array can be used as the K (key) of the map, but the slice cannot. The slice does not implement the equality operator. There are many problems to be considered, such as:

  • It involves shallow and deep comparison.
  • Pointer and value comparison.
  • How to handle recursive types.

Equality is defined for structures and arrays, so this type can be used as a map key. There is no equal definition of slice, and there is a very fundamental gap.

Array comparability and equality, slicing can’t.

Compilation security

Arrays can provide higher compile time security and can check the index range at compile time. As follows:

s := make([]int, 3)
s[3] = 3 // "Only" a runtime panic: runtime error: index out of range

a := [3]int{}
a[3] = 3 // Compile-time error: invalid array index 3 (out of bounds for 3-element array)

Although the help of this compilation check is “small”, it is actually very meaningful. I can recite the warning of major slices crossing the boundary every day

If the cross-border is on the hot path, affecting a large number of users, carrying an accident every minute and another 3.25, wouldn’t you wake up in a dream?

The compilation of array is safe, and slicing cannot be done.

Length is type

The length of the array is part of the array type declaration, soArrays of different lengths are different types, two are not one thing.

Of course, this is a double-edged sword. The advantage is that it can be used to explicitly specify the length of the desired array.

For example, you want to write a function using IPv4 address in business code. Can declaretype [4]byte。 Use arrays with the following awareness:

  • With the guarantee of compile time, that is, the value of the function passed to you will have exactly 4 bytes, no more and no less.
  • If the length is wrong, it can be considered as an invalid IPv4 address, which is very convenient.

At the same time, the length of the array can also be used for recording purposes:

  • MD5 type, incrypto/md5In the bag,md5.SumMethod returns a value of type,[Size]byteamongmd5.SizeA constant is the length of the 16: MD5 checksum.
  • IPv4 type, declared[4]byteFour bytes were recorded correctly.
  • RGB type, declared[3]byteTell there is 1 byte for each color component.

In specific business scenarios, it is better to use arrays.

Planning memory layout

Array can better control the memory layout, because you can’t allocate space directly in the structure with slices, so you can use array to solve it.

For example:

type Foo struct {
    buf [64]byte
}

I don’t know if you have seen such unknown operations on some go graphics libraries. Examples are as follows:

type TGIHeader struct {
    _        uint16 // Reserved
    _        uint16 // Reserved
    Width    uint32
    Height   uint32
    _        [15]uint32 // 15 "don't care" dwords
    SaveTime int64
}

Because of business requirements, we need to implement a format, where the format is “TGI” (theoretically go image), and the header contains such fields:

  • There are 2 reserved words (16 bits each).
  • There is an image width of 1 word.
  • There is an image height of 1 word.
  • There are 15 bytes of business that don’t care.
  • There is a save time. The save time of the image is 8 bytes, which is the number of nanoseconds since UTC on January 1, 1970.

From this perspective, it is not difficult to understand the advantages of arrays in this scenario. Fixed length, controllable memory is very useful in planning memory layout.

Access speed

When using arrays, it is more efficient to access (single) array elements than slice elements, and the time complexity is O (1). For example:

var a [2]string
 A [0] = "brain in"
 A [1] = "fried fish"
 fmt.Println(a[0], a[1])

Slicing is not so convenient. To access the index value at a certain location, you need to:

 var a []int{0, 1, 2, 3, 4, 5}  
  number := numbers[1:3]

It’s more complicated to delete the value on the specified index bit. There may be some small partners struggling for a long time, and even looking for a third-party open source library to implement it quickly.

In terms of access speed and development efficiency, arrays have certain advantages, which can not be directly compared by slices.

summary

After a round of discussion, we have a deeper understanding of the array of go language. The summary is as follows:

  • Arrays are value objects that can be compared and used as mapping keys for maps. These slices can’t be compared and can’t be used as the mapping key of map.
  • The array has compilation security check, which can avoid cross-border behavior in the early morning. Slicing is a panic that goes out of bounds at run time, with different stages.
  • Array can better control the memory layout. If you replace it with slices, you will find that you can’t allocate space directly in the structure with slices. Array can.
  • Arrays perform better than slices when accessing a single element.
  • The length of the array is part of the type. It has certain significance in a specific scene.
  • Array is the basis of slice. Every array can be a slice, but not every slice can be an array. If the value is a fixed size, you can get a small performance improvement by using arrays (at least saving the space occupied by slice headers).

Is it consistent with the advantages of the array in your mind? Welcome to discuss and communicate in the comment area.

I’m fried fish. I’ll see you next time:)

If you have any questions, you are welcome to feedback and exchange in the comment area,The best relationship is mutual achievement, everybodygive the thumbs-upnamelyFried fishThe greatest driving force of creation, thank you for your support.

The article is continuously updated. You can search [brain into fried fish] on wechat to read and reply【000】I have prepared the first-line large factory interview algorithm solutions and materials.

this paperGitHub github.com/eddycjy/blogHas been included, welcome star reminder.

reference resources

  • In GO programming language what are the benefits of using Arrays over Slices?
  • Why have arrays in Go?