HomeArchitectureIt is time to Go: our journey into grown-up code part 8

It is time to Go: our journey into grown-up code part 8

This is the eighth article in our series in learning GO, the first seven articles can be found here:

  1. It is time to “Go” and learn how to code with Go
  2. It is time to Go: our journey into grown-up code part 2
  3. It is time to Go: our journey into grown-up code part 3
  4. It is time to Go: our journey into grown-up code part 4
  5. It is time to Go: our journey into grown-up code part 5
  6. It is time to Go: our journey into grown-up code part 6
  7. It is time to Go: our journey into grown-up code part 7

To date, our journey has covered a lot of ground, and we have slowly built up an understanding of several core features and concepts.  We are truly building firm foundations.

  • The core Variables types
  • Variadic variables
  • Redeclaration
  • Constants
  • inputs
  • Structs
  • Pointers
  • Interfaces
  • Function basics
  • Conditional statements, if statements and switch statements.
  • Loops, breaks, deferment, continue, goto, return and recover
  • Range
  • Importation of built-in functions (“fmt”, “sync”, “reflect”, “strings”, “strconv”)
  • Arrays

At the end of our last article, we had extended our understanding of arrays by looking the various methods of how to create, and manipulate them. We also grappled with a thorny problem of how to pass a multi-type map, one initialised from a integer and a string, to an array and started to convert data types using the built-in function “strconv.Iota”.

What are we looking at today?

Today we will start to look at the array’s kissing cousin the “slice”.  In Golang the slice and array may appear very similar, but there are several significant differences.  The main difference is that an array is a value-type but a slice is a reference type.

What does that mean?

In Go language, officially there are no reference types. There is only values and pointers. That all said, pointer is for all intents and purpose a ‘reference’, and it is only purism that states it is not 😊.  There are certain types in Go are pointers (or reference) types, some we have already discussed, for example maps and Functions, and today we are going to discuss slices, and some we have not yet had the pleasure of meeting for example channels, and methods.

Now an Array in Go is a value type, not reference type. This means that when an array is assigned to a new variable, then the changes made in the new variable do not affect the original array.  In other words, the array is either duplicated and manipulated, or re-declared with new values.

So, what are the differences between a Slice and an array, other then one is a pointer and the other a value type.  A slice can be either a full complete array, or a part of an array. However, unlike an array where the size of the array has to be declared, with a slice this is not necessary, Also, when a slice is made from an array it can contain or share data items from the parent array.

As we have said Slices are similar to arrays, but are more powerful and flexible.  If you are an infrastructure guy, as I am, a possible analogy that would appear to fit would be that of a virtual machine against a physical machine.  They both provide the same function, run an operating system and overlaying application. But the virtual machine has the benefit of abstraction, and is able to move from underlaying host to underlaying host,  a Slice can be considered an abstraction of an array.  Unlike arrays they are not fixed in size, they can be resized dynamically.

So now we have an understanding of what a slice is and how it differs from an array lets create our first slice.

package main
import "fmt"
func main() {
    arr := [5]int{1, 2, 3, 4, 5}
    slice := arr[1:3]
    fmt.Println(slice)
}

In this example, we have created an array of integers with a length of 5 and assigned it to the variable ”arr”, finally we gave it the values of “1 through to 5”. We have then created a slice which we have called ”slice” by slicing the array from index 1 to index 3 (exclusive). The resulting slice will contain the elements “[2, 3]”, this is because array indexes start at “0”.  Running this code result I the following response:

This is a Slice in go.
This is our first slice, in Go, not in bread.

Now that we understand how to create a slice from an array let’s start to get a little bit funky. Remember our code that pulled all the prime numbers from the values 2-99,  let’s revisit that by creating an package that will create an array with all the numbers between 2-99 then create two slices, one of all the prime numbers and the second containing all the composite numbers.

package main
import (
  . "fmt"
)
func main() {
  var arr [98]int
  for i := 0; i < len(arr); i++ {
      arr[i] = i + 2
  }
  var primes []int
  var composites []int
  for _, num := range arr {
     isPrime := true
     for i := 2; i < num; i++ {
         if num%i == 0 {
             isPrime = false
             break
         }
     }
     if isPrime {
         primes = append(primes, num)
         } else {
         composites = append(composites, num)
         }
     }
     Println("Primes:", primes)
     Println("Composites:", composites)
}

By now we should be starting to instinctively understand the flow of the code, but first block of code is our variable declaration that creates an array called “arr” of 98 integer entities.  Next we create a nice little for loop to fill the array with values.

Next we create two variables that will hold our slices, the first slice is called “primes” and the second “compsites”, the next for loop creates the magic,  populating the “prime” and “composite” slices with their respective values,  it does this by looping through each number in the array to determine if it’s prime or composite.

isPrime := true
    for i := 2; i < num; i++ {
        if num%i == 0 {
          isPrime = false
          break
        }
}

If it’s prime, it’s added to the “primes” slice, and if it’s composite, it’s added to the “composites” slice.

if isPrime {
  primes = append(primes, num)
  } else {
  composites = append(composites, num)
}

Finally, we print out the resultant slices.  Running the above code results in the following response.

Oh look, primes and compsites
oh, look, we have our primes and composites split into two slices

So far we have only interacted with the standard terminal output, this would be very limiting if that was all that can be done, so it is time to enhance our previous code, and introduce some more building functions from the standard library.

It is time to go web style

Just like previously we are going to create two slices, however instead of just outputting them to the standard output in a terminal, we are going to have the responses exported to a HMTL page for display in a browser.  This is our code.

package main
import (
    "fmt"
    "html/template"
    "math"
    "net/http"
)
func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}
func handler(w http.ResponseWriter, r *http.Request) {
    var primes []int
    var composites []int
    for i := 2; i <= 99; i++ {
        if isPrime(i) {
            primes = append(primes, i)
        } else {
            composites = append(composites, i)
        }
    }
    tmpl := template.Must(template.ParseFiles("index.html"))
    data := struct {
        Primes     []int
        Composites []int
        }{
        primes,
        composites,
        }
        err := tmpl.Execute(w, data)
        if err != nil {
            fmt.Println(err)
        }
}
func isPrime(n int) bool {
    if n <= 1 {
        return false
    }
    for i := 2; i <= int(math.Sqrt(float64(n))); i++ {
        if n%i == 0 {
            return false
        }
    }
    return true
}

The first thing you will note is that there are three new imported functions from the standard library,

"html/template"
"math"
"net/http"

The first html/template implements the capability to generate HTML output, this is similar to the text/template package but is preferred when dealing with HTML.  We also have “net/http” this package provides the capability to interact with http clients and servers. It can be used to provide Get, Head Post and Postform requests and can handle a number of other functions too.  The final functions is “math”, this provides basic constants and mathematical functions, now we could leave this out and use our original code to test whether a number is prime or composite, but it is important to get used to utilizing the standard library, it will prevent a lot of navel gazing and reinvention of the wheel.

Another thing to note with this code is that we have multiple functions, the first is our already well known “func main (){}”,  we have been writing code for a while now with this special function, wait what now?  What is special about “func main”.  We already know that it is the most basic function in golang, it’s primary purpose is to act as the entry point for the packages role.  It must be noted that there can only be one “func main ()” in any package. However, it also serves another more important function as it acts as a wrapper for all the code in the package.   This is what makes the concept of the “package” useful, as all that is needed to utilise code within a package is to “import” the package.  More on this later.

Our function main, creates a http service that is listening on port 8080.  One thing to note is that this function will continue running until the program is explicitly terminated.

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

Our program has two extra functions, at first look these appear complex, and several weeks ago I would have concurred with that statement, but just like elementary French, I am starting to pick up patterns and understanding is starting to blossom.

Let’s look at what the first function “func handler” is doing.

func handler(w http.ResponseWriter, r *http.Request) {
    var primes []int
    var composites []int
    for i := 2; i <= 99; i++ {
          if isPrime(i) {
             primes = append(primes, i)
             } else {
             composites = append(composites, i)
            }
         }
         tmpl := template.Must(template.ParseFiles("index.html"))
           data := struct {
               Primes     []int
               Composites []int
           }{
               primes,
               composites,
          }
          err := tmpl.Execute(w, data)
          if err != nil {
             fmt.Println(err)
         }
}

The “handler” function creates a HTTP request handler that generates two slices, one that holds all prime numbers from 2-99 and the other that contains all composite numbers from 2-99, these slices are then displayed as two tables in an HTML page.

Breaking this down further, the “http.ResponseWriter” option is utilised to write the response back to the client, while the “http.Request” parameter is used to store information about the incoming request. Both these are a part of the “http” library.

We create two slice variables

var primes []int
var composites []int

and fill them with the for loop

for i := 2; i <= 99; i++ {
    if isPrime(i) {
        primes = append(primes, i)
        } else {
        composites = append(composites, i)
    }
}

As we have previously discussed loops to exhaustion 😊, there is nothing new to see here.

tmpl := template.Must(template.ParseFiles("index.html"))
data := struct {
    Primes     []int
    Composites []int
    }{
    primes,
    composites,
    }
    err := tmpl.Execute(w, data)
    if err != nil {
       fmt.Println(err)
    }
}

The line ”template.Must(template.ParseFiles(“index.html”))” parses the template file “index,html” and provides a pointer to a new template object. If there is an error processing the template file, the “Must” function panics; for example, if the file “index.html” is missing.  The “data” variable is a struct with two fields: “Primes”, the slice of prime numbers, and “Composites”, the slice of composite numbers. Finally, the “tmpl.Execute(w, data)” line creates an HTML page by referencing a template file called “index.html”, which contains placeholders for the prime and composite number slices.

func isPrime(n int) bool {
    if n <= 1 {
       return false
    }
    for i := 2; i <= int(math.Sqrt(float64(n))); i++ {
        if n%i == 0 {
            return false
        }
    }
    return true
}

The “isPrime(n int) bool” function determines whether or not a given integer is prime by iterating through all numbers from 2 to the square root of n and determining whether or not any of them divide “n” evenly.

One thing further thing to note is that we mentioned “index.html”, this is a web page template file the is needed to display our result in a web browser.  As this is a discussion on GoLang, I do not intend to discuss this file.  It surfices to say that the file is needed to prevent a panic in the golang program.

<!DOCTYPE html>
<html>
<head>
    <title>Primes and Composites</title>
</head>
<body>
    <h1>Primes</h1>
    <table>
        {{range .Primes}}
        <tr><td>{{.}}</td></tr>
        {{end}}
    </table>
    <h1>Composites</h1>
    <table>
        {{range .Composites}}
        <tr><td>{{.}}</td></tr>
        {{end}}
    </table>
</body>
</html>

When we run the code, you will notice that unlile previously there is no response at the terminal.

well that is not interesting
Oh, where has our Output gone?

As expected the process just rest there and will do so until we explicitly terminate it with a “ctrl+c” command.  OK so where do we actually see our output, we remember we created a http service that is listening on port 8080.  Well we simply point our local browser at the following address:

there is no place like home
There is no place like home,

You could also use,

it can also be a localhost.
it seems our house has a name.

After doing this, we can see the following displaying on our page.

here is our output,
Here is our output, it looks a lot fancier now doesn’t it?

Summary

Once again, we have covered a lot of ground we have discussed the difference and commonality between Arrays and Slices, and then introduced a new output for our code,  the introduction of HTML built in functions and the math function.  we are starting to get to the position were we can start to look at doing something useful with our knowledge.

NEWSLETTER

Receive our top stories directly in your inbox!

Sign up for our Newsletters

spot_img
spot_img

LET'S CONNECT