1

Hello everyone, I am fried fish.

There was a newsletter that was broadcast some time ago, that is, Go1.17 will officially support the conversion of slices (Slice) to data (Array). It is no longer necessary to use the previous method, which is much safer.

However, some students raised new doubts. In the Go language, arrays are actually used relatively little. Some students even think that arrays can be removed in Go.

图片

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

This is a question that we need to delve into, so let's take a look with you today. This article will first briefly introduce what arrays and slices are, and then further analyze the usage scenarios of arrays.

Let's happily start the road of fish-sucking together.

What is array

There is a basic data type in the Go language called an array. The format is: [n]T . Is an array containing N values of type T.

The basic declaration format is:

var a [10]int

It means that a variable a is declared as an array containing 10 integers. The length of the array is part of its type, so the array cannot be arbitrarily resized.

In the usage example:

func main() {
 var a [2]string
 a[0] = "脑子进"
 a[1] = "煎鱼了"
 fmt.Println(a[0], a[1])
 fmt.Println(a)

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

Output result:

脑子进 煎鱼了
[脑子进 煎鱼了]
[2 3 5 7 11 13]

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

What is slice

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

The basic declaration format is:

var a []T

It means that the variable a is a slice T with type elements. A slice is formed by specifying two indexes (lower limit and upper limit) and separated by colons:

a[low : high]

In the usage example:

func main() {
 primes := [3]string{"煎鱼", "搞", "Go"}

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

Output result:

[搞 Go]

Slicing supports dynamic expansion and contraction, which does not require the user's attention, which is very convenient. More importantly, the underlying data structure of the slice itself contains an array:

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

Many people also laughed and said: has been laid off in the Go language array, and it is done with slicing ...

What do you think of this statement, think quickly about the answer in your mind.

Advantages of arrays

After introducing the basic scenes of arrays and slicing, let’s learn about the official readme first in terms of 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 rude and indirect: Arrays are useful when planning the detailed layout of memory, and can sometimes help avoid allocation, but mainly because they are the building blocks of shards.

Let's interpret it further and see what the official "ciphertext" specifically refers to. We will interpret the ciphertext as the following to explain:

  • Comparable.
  • Compilation safety.
  • The length is the type.
  • Plan the memory layout.
  • Access speed.

Comparable

Arrays are of fixed length, and they can be compared. Arrays are value objects (not reference or pointer types). You will not encounter misjudgments such as interface comparisons:

func main() {
 a1 := [3]string{"脑子", "进", "煎鱼了"}
 a2 := [3]string{"煎鱼", "进", "脑子了"}
 a3 := [3]string{"脑子", "进", "煎鱼了"}

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

Output result:

false true

On the other hand, slices cannot be directly compared, nor can they be used for judgment:

func main() {
 a1 := []string{"脑子", "进", "煎鱼了"}
 a2 := []string{"煎鱼", "进", "脑子了"}
 a3 := []string{"脑子", "进", "煎鱼了"}

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

Output result:

# 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 does not work. The slice does not implement the equality operator. There are many issues to consider, for example:

  • Involving shallow and deep comparisons.
  • Pointer and value comparison.
  • How to deal with recursive types.

Equality is defined for structures and arrays, so these types can be used as map keys. There is no equal definition of slicing, and there is a very fundamental gap.

Comparability and equality of arrays cannot be done with slicing.

Compile safe

Arrays can provide higher compile-time safety, and the index range can be checked 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 see the alarms that the major slices have crossed the boundary every day, and I feel that I can memorize it...

In case this cross-border is on the hot path and affects a large number of users, if you recite an accident every minute, and then another 3.25, won't you wake up in your dream?

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

Length is type

The length of the array is part of the array type declaration, so arrays with different lengths are of different types , and two are not the same "thing".

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

For example: You want to write a function that uses an IPv4 address in your business code. You can declare type [4]byte . Use arrays have the following awareness:

  • With the guarantee at compile time, that is, the value passed to your function will have exactly 4 bytes, no more, 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, in the crypto/md5 package, the md5.Sum method returns a value of type, [Size]byte where md5.Size is 16: the length of the MD5 checksum.
  • IPv4 type, the declared [4]byte correctly records 4 bytes.
  • For the RGB type, the statement [3]byte tells that there is 1 byte for each color component.

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

Planning the memory layout

Arrays can better control the memory layout, because you can't directly allocate space in the structure with slices, so you can use arrays to solve it.

E.g:

type Foo struct {
    buf [64]byte
}

I don’t know if you have seen this kind of unknown operation 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" (Go Image in theory), 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 business "don't care" bytes.
  • There is 1 storage time, and the image storage time is 8 bytes, which is the number of nanoseconds since UTC on January 1, 1970.

Looking at it this way, it is not difficult to understand the advantages of arrays in this scenario. Fixed-length, controllable memory is very useful when planning memory layout.

Access speed

When using arrays, accessing (single) array elements is more efficient than accessing slice elements, and the time complexity is O(1). E.g:

 var a [2]string
 a[0] = "脑子进"
 a[1] = "煎鱼了"
 fmt.Println(a[0], a[1])

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

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

More complicated, delete the value on the specified index bit, there may be small partners who struggle for a long time, and even look for a third-party open source library to quickly implement it.

Regardless of access speed and development efficiency, arrays have certain advantages, which cannot be directly compared with slices.

Summarize

After a round of discussion, we have a deeper understanding of Go language arrays. Summarized as follows:

  • Arrays are value objects and can be compared. Arrays can be used as map keys. However, none of these can be sliced, cannot be compared, and cannot be used as a map key.
  • Arrays are checked for compilation safety to avoid out-of-bounds behavior early on. Slicing is a panic that is out of bounds at runtime, and the stages are different.
  • Arrays can better control the memory layout. If you replace with slices, you will find that you cannot allocate space directly in the structure with slices. Arrays can.
  • The performance of arrays is better than slices when accessing a single element.
  • The length of the array is part of the type. It has a certain meaning in a specific scenario.
  • Arrays are the basis of slices. Each 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 an array (at least saving the space occupied by the slice header).

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

I'm fried fish, see you next time :)

If you have any questions, welcome feedback and communication in the comment area. The best relationship between . likes is fried fish . Thank you for your support.

The article is continuously updated, and you can read it through search [My brain is fried fish], and reply [1614abf65b3190 000 ] There are the first-line interview algorithm questions and information prepared by me.
This article GitHub github.com/eddycjy/blog has been included, welcome Star to remind you.

refer to

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

煎鱼
8.4k 声望12.8k 粉丝