Go 5 Interesting Concepts as a js developer
Tags: go, webdev, javascript, beginners
Published: 2022-07-03 17:41:19

Go 5 Interesting concepts as a js developer

## What is Go

- Statically Typed
- Compiled language
- Easy to learn
- Fast
- Concurrency

Go is an open source programming language supported by google. It's easy to learn and has high performance and powerful tools. You can easily make concurrent programs with goroutines.

It's commonly used for server programming like Web Development and Cloud & Network Services. Actually, you can develop any programs you want with it.

---

## 5 Interesting concepts as a js developer

- For loop
- Structs
- Arrays and Slices
- Handling Errors
- Goroutines

---

### For loop

In most languages, there are loops while, do-while and for.

Go has only one looping construct. the for loop.
But it has various shapes.

#### For

javascript
```javascript
for (let i = 1; i <= 5; i++) {
  console.log(i);
}
```

go
```go
for i := 1; i <= 5; i++ {
	fmt.Println(i)
}
```

#### while

javascript
```javascript
let i = 1;
while (i <= 5) {
  console.log(i);
  i++;
}
```

go
```go
i := 1;
for i <= 5 {
	fmt.Println(i)
	i++
}
```

#### Infinite Loop

javascript
```javascript
while (true) {
  console.log('hello, go!');
}
```

go
```go
for {
	fmt.Println(i)
	
```

#### For Each

javascript
```javacsript
const array = [1,2,3,4,5];
for (const value of array) {
  console.log(value);
}
```

go
```go
array := [5]int{1,2,3,4,5}
for _, value := range(array) {
	fmt.Println(value);
}
```

### no do-while

Only one loop. I think it's more clear than having a few loops. And Supporting infinite loop is also interesting. 

---

### Structs

A struct is a collection of data fields with declared data types. It seems like an interface. you can also attach methods into the struct.

javascript
```javascript
class Company {
  employees = [];

  hire(...newEmployees) {
    for (const employee of newEmployees) {
      this.employees.push(employee);
    }
  }

  print() {
    for (const employee of this.employees) {
      console.log(employee.name);
    }
  }
}

class Employee {
  constructor(name) {
    this.name = name;
  }
}

const newCompany = new Company();

newCompany.hire(
  new Employee("lico"),
  new Employee("lavine"),
  new Employee("dave")
);
newCompany.print();
```

```go
package main

import (
	"fmt"
)

type Employee struct {
	Name string
}

type Company struct {
	employees []*Employee
}

func (company *Company) Hire(newEmployees ...*Employee) {
	for _, employee := range(newEmployees) {
		company.employees = append(company.employees, employee)
	}
}

func (company *Company) Print() {
	for _, e := range(company.employees) {
		fmt.Println(e.Name)
	}
}

func main() {
	newCompany := Company{}

	newCompany.Hire(
		&Employee{Name: "lico"},
		&Employee{Name: "lavine"},
		&Employee{Name: "dave"},
	)
	newCompany.Print()
}
```

I'm also working on typescript projects, so, declaring types is not strange for me. But the way to attach methods to the struct is a little confused at the first time. And we don't use the concept "pointer". I think it's important to get familiar with the pointer concept. the memory. It's below the title 'struct' though, I'll show some examples for understanding the asterisk keyword next by struct names. (`func (company *Company) ...`)

```go
import (
	"fmt"
)

type Pointer struct {
	Name string
}

func (pointer *Pointer) Change() {
	pointer.Name = "Someone"
}

type NoPointer struct {
	Name string
}

func (noPointer NoPointer) Change() {
	noPointer.Name = "Someone"
}

func main() {
	pointer := Pointer{Name: "lico"}
	noPointer := NoPointer{Name: "lico"}

	pointer.Change()
	noPointer.Change()

	fmt.Printf("pointer: %s, noPointer: %s\n", pointer.Name, noPointer.Name)
}
```

```
pointer: Someone, noPointer: lico
```

When you define functions with the asterisk keyword, you can access itself. you must consider the cost of copying objects.

---

### Arrays and Slices

There are arrays and slices in Go. Arrays have fixed sizes but slices have flexible sizes. I expect the arrays are safer than slices because it's expected. 

```go
func main() {
	nums := [5]int{1,2,3,4,5}
	fmt.Printf("nums len: %d, cap:%d\n", len(nums), cap(nums))
	fmt.Println(nums)
}
```

```
nums len: 5, cap:5
[1 2 3 4 5]
```

Arrays can't be resized but slices can.

```go
func main() {
	nums := []int{1,2,3,4,5}
	nums = append(nums, 1)

	fmt.Printf("nums len: %d, cap:%d\n", len(nums), cap(nums))
	fmt.Println(nums)
}
```

```
nums len: 6, cap:10
[1 2 3 4 5 1]
```

You can use resize with `append`. you might have noticed that the `capacity` turned into `10`. 
If you append one more,

```go
func main() {
	nums := []int{1,2,3,4,5}
	nums = append(nums, 1)
	nums = append(nums, 2)

	fmt.Printf("nums len: %d, cap:%d\n", len(nums), cap(nums))
	fmt.Println(nums)
}
```

```
nums len: 7, cap:10
[1 2 3 4 5 1 2]
```

You must see like this. There are `length` and `capacity` in Go.
`length` is the length of the arrays or slices and `capacity` is the space that elements can settle in.
When appending an element, if the `capacity` is not enough, Go allocates new space and copies all of them to it.

```go
func main() {
	nums := []int{1,2,3,4,5}
	numsA := append(nums, 1)
	numsA[1] = 10
	numsB := append(numsA, 2)
	numsB[2] = 20

	fmt.Printf("%p %p %p\n", nums, numsA, numsB);
	fmt.Println(nums)
	fmt.Println(numsA)
	fmt.Println(numsB)
}
```

```
0xc00000a360 0xc00000c280 0xc00000c280
[1 2 3 4 5]
[1 10 20 4 5 1]
[1 10 20 4 5 1 2]
```

When `numsB` was created, there was enough space. So, in this time `numbB` wasn't reallocated. This is why `numsA` was affected with changing a value of `numbsB`.

You can make a slice from arrays.

```go
func main() {
	nums := [8]int{1,2,3,4,5,6,7,8}
	numsA := nums[4:]

	numsA[1] = 10

	fmt.Printf("nums len:%d cap:%d\n",len(nums), cap(nums))
	fmt.Println(nums)
	fmt.Printf("numsA len:%d cap:%d\n",len(numsA), cap(numsA))
	fmt.Println(numsA)
}
```

```
nums len:8 cap:8
[1 2 3 4 5 10 7 8]
numsA len:4 cap:4
[5 10 7 8]
```

`numsA` shared the memory space with `nums`. It's an also important concept of `slices`.

```go
func main() {
	nums := [8]int{1,2,3,4,5,6,7,8}
	numsA := nums[4:]

	numsA = append(numsA, 50)
	numsA[1] = 10

	fmt.Printf("nums len:%d cap:%d\n",len(nums), cap(nums))
	fmt.Println(nums)
	fmt.Printf("numsA len:%d cap:%d\n",len(numsA), cap(numsA))
	fmt.Println(numsA)
}
```

```
nums len:8 cap:8
[1 2 3 4 5 6 7 8]
numsA len:5 cap:8
[5 10 7 8 50]
```

`Slices` that are made from `Arrays` is also able to expand.

In `javascript`, there is not much to care about when using `Arrays`. It will get used to it but it took a bit of time to understand at the first time.

---

### Handling Errors

I might have not handled errors well in js. Error handling in Go, It's kind of fun though, it's really difficult. I haven't understood well yet so, I will show some basic examples about it.

javascript
```javascript
function devide(a, b) {
  if (b === 0) throw new Error("devided by zero");
  return a / b;
}

try {
  console.log(devide(100, 0));
} catch (e) {
  console.log(e);
}
```

go
```go
func devide(a int, b int) (int, error) {
	if b == 0 {
		return 0, errors.New("devided by zero")
	}

	return a / b, nil
}

func main() {
	result, err := devide(100, 0)

	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(result);
}
```

Writing more code in Go than in javascript.
Let's say, there is an error that you don't expect. How can we prepare for accidental errors?

```go
func devide(a int, b int) int {
	return a / b
}

func main() {
	fmt.Println(devide(10, 0));
}
```

```
panic: runtime error: integer divide by zero

goroutine 1 [running]:
main.devide(...)
        C:/Users/hskco/OneDrive/바탕 화면/dev/example-a/go/main.go:8
main.main()
        C:/Users/hskco/OneDrive/바탕 화면/dev/example-a/go/main.go:12 +0x12
exit status 2
```

You would encounter the panic with the code. You can recover the panic using `recover` in a defer function.

```go
func devide(a int, b int) int {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("devided by zero")
		}
	}()
	return a / b
}

func main() {
	fmt.Println(devide(10, 0));
}
```

```
devided by zero
0
```

When errors occur, defer functions would be called. Also, defer functions are called after the function execution.

```go
func test() {
	defer func() {
		fmt.Println("defer")
	}()
	fmt.Println("test")
}

func main() {
	test()
}
```

```
test
defer
```

You can clean up resources in the function. multiple defer functions are available as well.

```go
var (
	CUSTOM_ERROR = errors.New("CUSTOM_ERROR")
)

func test() error {
	return CUSTOM_ERROR;
}

func main() {
	err := test()

	if err == CUSTOM_ERROR {
		fmt.Println("Custom Error")
	}
}
```

It is a part of custom errors. It has a lot of features for custom errors.

---

### Goroutines

Although there are features like workers, javascript is a single-threaded language.

Go has goroutines. A goroutine is a lightweight thread managed by the Go runtime. 

They can communicate with other goroutines with low latency using channels.

```go
func print(wg *sync.WaitGroup, nCh <-chan int) {
	defer wg.Done()

	// Receive an element from the channel
	for n := range(nCh) {
		// Print numbers
		for i := 1; i <= n; i++ {
			fmt.Println(i)
		}
	}
}

func main() {
	var wg sync.WaitGroup
	nCh := make(chan int)
	list := [...]int{10, 20, 30, 40, 50, 60}
	
	wg.Add(2)

	for i := 1; i <= 2; i++ {
		go print(&wg, nCh)
	}

	for _, n := range(list) {
		// Send an element
		nCh <- n
	}

	// Close the channel and wait the goroutines
	close(nCh)
	wg.Wait()
	fmt.Println("Done")
}
```

Writing `go` keyword in front of the function name for executing a function in background. This is a goroutine.

sync.WaitGroup is used for preventing the exit program. When the main function is finished, all goroutines exit.

Channel is used for communicating with goroutines.

close(nCh) notifies that the channel is closed, then goroutines will break from `for n := range(nCh)`.

---

### Conclusion

It's been a long time since I learned a new language. It says easy to learn go, but for me it was not that easy to learn it. there were many concepts that weren't in javascript. But it's worth it. Every language has its own philosophy. I think learning a new language would be helpful even if you don't often use the language. I'm working as a frontend engineer, so, someone might say that's not that useful though, I really enjoyed it. 

I'm sure it's going to be useful even while I'm 
working on a frontend project with js. And I can also make a server for my personal projects.

---

Which language are you interested in these days?