Learning Go - day 2
Tags: go, beginners, programming
Published: 2022-05-25 16:38:02

I should rather title it - part 2 not day 2 because I learned all those things in one day but it took me 4 days to write those notes and still they are not full. But writing is also part of learning. 

## 1. For loops and if statements

`for loops` and `if statements` are quite simple to use. But to use them correctly we need to understand two things: blocks and scopes.

### What's a block? 

Code in Go can be divided into segments that are called blocks. Blocks are usually parts of the code between curly brackets. They can be nested. When we are creating a for loop, everything that's between curly brackets is a block. If we put if statements inside a for loop, every part of code between moustache (curly) brackets creates a block. 

```go
for num := 1; num <= 10; num++ {
    if num % 2 == 0 {
        fmt.Println(num, "is an even number.")
    } else if num % 2 != 0 {
	fmt.Println(num, "is an odd number.")
    }
}
```
So there are 3 blocks of code in the example above.

### What's the scope?

The scope of variables is connected with blocks. When we declare a variable, it will be recognizable only within a block in which we declared it and blocks there are nested inside that block. So when we declare a variable inside one part of an `if statement`, it won't work in another part of `if statement` as well as outside the `if-else clause`. 

If I would like to change the previous code a bit and add a variable called answer like that: 

```go
for num := 1; num <= 10; num++ {		
    if num %2 == 0 {
        answer := "is an even number."
    } else if num%2 != 0 {
	answer := "is an odd number."		
    }		
    fmt.Println(num, answer)
}
```
	
Go won't let me do it. For the first two "answers" it will tell that the variable is declared and never used. And for the last "answer" it will say that this is an undeclared name. 

To fix it I need to declare the answer variable in the first block - for loop - like that: 	

```go
for num := 1; num <= 10; num++ {	
    var answer string	
    if num %2 == 0 {
	answer = "is an even number."
    } else if num%2 != 0 {
	answer = "is an odd number."		
    }		
    fmt.Println(num, answer)
}
```	

### What is continue and break?

Sometimes we want to finish the loop when a particular condition is met. So then we use the `break` statement. 
Let's imagine that we're looking for a number divided by 5 in a range from 1 to 10 (10 is included). And we're happy with the very first number we get. 

```go
for n := 1; n <= 10;n++ {		
    if n % 5 == 0 {
        fmt.Println(n, "is divided by 5")
	break
    } else {
	fmt.Println(n, "is not divided by 5")
    }
}
```
This short program will be running only as long as it comes to the very first number that can be divided by five: 5.

After running this loop (of course, it should be put inside the function to make it work in Go) we will see such an output:

1 is not divided by 5
2 is not divided by 5
3 is not divided by 5
4 is not divided by 5
5 is divided by 5

As we can see, my program stopped before checking all the numbers in the range. 

`Continue` doesn't stop the loop, but if we have something  after `continue` within the block in that statement, it won't check the code, only will go immediately to the next iteration of the loop.	

```go
for n := 1; n <= 10;n++ {		
    if n % 5 == 0 {
        fmt.Println(n, "is divided by 5")
	continue
        if (n == 5) {
	    fmt.Println("It's 5.")
	}
    } else {
        fmt.Println(n, "is not divided by 5")
    }
}
```

// output
1 is not divided by 5
2 is not divided by 5
3 is not divided by 5
4 is not divided by 5
5 is divided by 5
6 is not divided by 5
7 is not divided by 5
8 is not divided by 5
9 is not divided by 5
10 is divided by 5

The output shows that the block after `continue` wasn't executed at all. 

## 2. There's a package for everything

So far, I haven't been using many methods in Go but have noticed that to use almost all the functions and methods that are provided by Go, I first need to import the packages that contain them. 

If I want to print output, I need the `fmt` library and then one of the `Print()` functions. If I want to trim the next line character, I need the `strings` package and the `TrimSpace()` function. 

But things are getting a bit complicated when we want to use methods that are connected to values of a certain type. 
 
For example, when we want to get only a year from a date, we first have to import the `time` package. Then we will access the date using the Now() function that we need to assign to a variable. And only then we will use the method called Year(). 

```go
package main 

import (
	"fmt"
	"time"
)

func main() {
	var now time.Time = time.Now();
	var year int = now.Year()	
	fmt.Println(year)	
}
```

In that function, the first (now) variable's type is time.Time. The second (year) variable's type is an integer. 

Some of those methods return 2 values while we need and have only one variable. 
When we want to take input from a user, we need the `bufio` package and `NewReader()` function. In the code below I'm assigning `bufio.NewReader(os.Stdin)` to the `reader` variable.

`reader := bufio.NewReader(os.Stdin)`

The **type** of this variable is `bufio.Reader`. It's something very new to me. I was trying to print out the reader variable and it showed me something like that &{[0.....0] 0x0000e010 00 <nil> -1 -1}. At the moment I only understand that it's something binary. 

In other to be able to use the input from the command line, the next step is to assign the reader variable to another variable but we also have to call another method - `ReadString` - on it. 

`input := reader.ReadString('\n')  // it's got an error`

The rune \n in the brackets means the end of input data.

But we are not ready yet. The `ReadString` method wants to return us 2 values but we have only one variable assigned. One value is the input from the command line but the other value is usually the information about errors. Now, we have to handle the error. 

We will do it by adding the second variable:

```go
fmt.Print("Give me a number: ")
reader := bufio.NewReader(os.Stdin)
	
input, err := reader.ReadString('\n') // error again
	
fmt.Println(input)
```
The code won't compile again, because we always have to use all the declared values. We have two options. 

1. Use `_` (underscore) instead of err.

`input, _ := reader.ReadString('\n')`

This way we will ignore all information about errors from input data.

2. Or we can handle the error. Now we need one more package `log` and `Fatal()` function that will print us what error we have and will terminate our program. 

```go
input, err := reader.ReadString('\n')	
log.Fatal(err)	
fmt.Println(input)
```
But again, using `log.Fatal(err)` like that will stop the program even though the command line user typed something. 

We have to use `if statement` to show only when errors are not `nil`.  (nil is a zero value - everything I know so far about nil)

package main 

```go
import (
	"fmt"
	"bufio"
	"os"
	"log"
)

func main() {
	fmt.Print("Give me a number: ")
	reader := bufio.NewReader(os.Stdin)
	
	input, err := reader.ReadString('\n')
	if err != nil {
		log.Fatal(err)
	}	
	fmt.Println(input)
}
```

So many lines to only print the input data from the terminal. 

### One more thing to make packages more confusing ;-) 

Sometimes we want to import a package, for example, `rand` for generating random numbers but in the part of the code with imports, we need to give the import path - `math/rand`. It's so because packages that are from similar categories are grouped. And rand package is group together with other libraries for mathematical operations.

```go
package main 

import (
	"fmt"
	"math/rand"
)

func main() {
	target := rand.Intn(100) + 1
	fmt.Println(target)
}
```

The code above generates a random number in the range from 1 to 100. But only in theory. If we want to run this, we could see the same number. Every time we will run it. 

How to generate more random numbers? It's a story for another occasion.