Monday, April 19, 2021

Golang - Array

We frequently need to work with several values.

Before introducing Array, we must first understand how memory works.

Values in "Computer Memory" are stored in memory cells.

Each memory cell takes up one byte.


  | __ | __ | __ | __ | __ | __ | __ | __ | __ | __ |

            |cell| <= 1 byte


Variables can be assigned to different memory locations.


     1001 memory cell      1006 memory cell
                                    
  | __ | 0 | __ | __ | __ | __ | 0 | __ | __ | __ |
                                  
      var age1 byte          var age2 byte


An array's items are stored in contiguous memory cells.


  From 1001 to 1002, it is a single array value

       1001 1002 memory cell
            ↓   ↓
  | __ | 0 | 0 | __ | __ | __ | __ | __ | __ | __ |
         _______
            
          var ages [2]byte


Accessing values with contiguous memory cells is efficient for the CPU.

Let's look at the syntax.

The size of an array is indicated by the number enclosed in square brackets.

An array's size is equal to the sum of its items.


  [2]byte  => 2 * 1 byte = 2 bytes
  [2]int16  => 2 * 2 byte = 4 bytes

 
The most crucial thing to remember is that the array size is fixed.

We won't be able to update it later.

Uninitialized array elements will be set to "Zero Values" by Go.

Each array element is a variable with no name.

Furthermore, Go will not allow you to directly access the memory address.

Instead, Go provides a "index expression" that allows us to specify the element of an array we want to access.


  var ages [2]byte
  ages[0] = 5



Looping an array



"range" can be used to traverse across an array.
 

  for _g := range greetings {
    g += " has been changed!"
    fmt.Println(g)
  }
  
fmt.Printf("%q", greetings)

 
"range" will create a copy of the original array.

As a result, changing 'item' inside the range block has no effect on the original array.

You can alter the original array by using an index from the "range" array.

 
  for i_ := range greetings {
    greetings[i] += " has been changed!"
  }

  fmt.Printf("%q\n", greetings)

 

How to create an array?




  var greetings [3]string
  greetings[0] = "Hello"
  greetings[1] = "How are you"
  greetings[2] = "Good"


Is this the only method for creating and assigning elements to an array?

This method can be used to generate and initialize a new array with the specified values.


  var greetings = [3]string{
    "Hello",
    "How are you",
    "Good",
  }

  
We can even simplify it as seen below.

It is recommended that you use this format if you already have the element.


  greetings := [3]string{
    "Hello",
    "How are you",
    "Good",
  }


It is called "Array Literal" on the right side.

One of the composite literals is array literal.

Composite Literals are used to generate new composite values (like arrays) on the fly.

Format:

  type{
    item,
    item,
    item
  }


Go can automatically determine the length of an array by using 'ellipsis'.


  greetings := [...]string{
    "Hello",
    "How are you",
    "Good",
  }



Comparing arrays?



When the types of arrays are the same, they are similar.

Arrays are equal when their elements are equal, which means that Go will compare each array element one by one.

To illustrate the distinction, consider bellows.

Ex1:

  arr1 := [3]int{
    123,
  }
  arr2 := [3]int{
    123,
  }

  fmt.Println(arr1 == arr2)


Result:
            
true


Ex2:

  arr1 := [3]int{
    123,
  }
  arr2 := [3]int{
    143,
  }

  fmt.Println(arr1 == arr2)


Result:
            
false


Ex3:

  arr1 := [3]int{
    123,
  }
  arr2 := [4]int{
    123, 4,
  }

  fmt.Println(arr1 == arr2)


Error:
arr1 == arr2 (mismatched types [3]int and [4]int)



Assign an array to another one?



Only arrays of the same type can be assigned.

When we assign one array to another, Go creates a new memory location for the new array.

As a result, the old and new arrays are not linked.


  arr1 := [2]byte{
    12,
  }

  arr2 := arr1
  arr2[0] = 9

  fmt.Printf("%d\n", arr1)
  fmt.Printf("%d\n", arr2)


Result:

  [1 2]
  [9 2]


Memory cells:

  | __ | 1 | 2 | __ | __ | __ | 9 | 2 | __ | __ |
         _______                 _______
                                     
           arr1                    arr2



Array of array



Assume we want to calculate the sum of all the values in two arrays.
     

The simple version will look like:  

  sum := byte(0)
  cost1 := [3]byte{123}
  cost2 := [3]byte{456}

  for _c1 := range cost1 {
    sum += c1
  }

  for _c2 := range cost2 {
    sum += c2
  }

  fmt.Println(sum)

 
Go provides an additional structure for this circumstance.

It is made out of multidimensional arrays.

We referred to it as an array of arrays.

Consider the following example:

* The outer array is [2][3]bytes in size, with each element being an inside array.
* [3]btye is the value of the inner array.

    
  sum := byte(0)
  cost := [2][3]byte{
    {123},
    {456},
  }

  for _outer := range cost {
    for _inner := range outer {
      sum += inner
    }
  }

  fmt.Println(sum)



Get rid of the magic number



Take a look of this example below.

Ex:

  args := os.Args[1:]
  if len(args) != 1 {
    fmt.Println("[pass|fail]")
    return
  }

  mode := args[0]
  moods := [...][3]string{
    {
      "happy""good", "nice",
    },
    {
      "sad""bad", "terrible",
    },
  }

  rand.Seed(time.Now().UnixNano())
  n := rand.Intn(len(moods))

  switch mode {
  case "positive":
    fmt.Printf("%s\n", moods[0][n])
  case "negative":
    fmt.Printf("%s\n", moods[1][n])
  }


We found that there are two magic numbers in our program.

In our program, we discovered two magical numbers.

We should avoid utilizing magic numbers in best practice.

We can leverage Go's Keyed Element capability.

The index positions are described by keyed elements.

Each key corresponds to an array index.

    
args := os.Args[1:]
  if len(args) != 1 {
    fmt.Println("[pass|fail]")
    return
  }

  mode := args[0]
  moods := [...][3]string{
    {
      "happy""good", "nice",
    },
    {
      "sad""bad", "terrible",
    },
  }

  const (
    pass = iota
    fail
  )

  rand.Seed(time.Now().UnixNano())
  n := rand.Intn(len(moods))

  switch mode {
  case "positive":
    fmt.Printf("%s\n", moods[0][n])
  case "negative":
      fmt.Printf("%s\n", moods[fail][n])
  }


No comments:

Post a Comment