Google’s Go Essentials For Node.js / JavaScript Developers

Google’s Go Essentials For Node.js / JavaScript Developers
Keep checking this article as I will make it more comparative between Go and Node constructs. This article will be a brain dump of all I’ve learned so far about Google’s Go language.

Originally published by Florian GOTO at medium.com

(Keep checking this article as I will make it more comparative between Go and Node constructs.)

As an advanced JavaScript developer, The more I work with JavaScript the more I understand the advantages of a statically typed language.

Paradoxically, it is easier to make TypeErrors in JavaScript than in other languages I have used. When you do work on the back-end, it is unacceptable. On the front end, when you are a little bit serious about your work, you notice how so many JS developer do NOT understand the typing system in JavaScript because it is not forced on them. That’s why there is a lot of garbage JS code in the world.

JavaScript is HARD when you get serious about understanding it under the hood. So many (kind of hidden) complex concepts you have to understand in order to make sense of the errors in your code (or why it’s working but that’s not the correct way to do it…).

JavaScript is fascinating but sometimes you want to try something else and broaden your horizon.

This article will be a brain dump of all I’ve learned so far about Google’s Go language.

I assume you have installed the Go binaries on your computer.


Variables

package main

import “fmt”

func main() {
// you MUST use a declared variable otherwise compilation error

var toto int8 = 123
fmt.Println(toto)

var tito = 123
fmt.Println(tito)

// variable declaration with type inference
toti := 123
fmt.Println(toti)

// variable declaration (implicitly initialized to zero-value,// for numeric types = 0)
var tata int
fmt.Println(tata)

// variable assignment
tata = 951
fmt.Println(tata)

}

Number Types

package main

import “fmt”

func main() {
// Go does not convert types automatically
// need to explicitly convert them
var (
i int8 = 20
f float32 = 5.6
)
fmt.Println(i + int8(f+1.9))

var (
    j int32 = 456
    k int64 = 987654
)
fmt.Println(int64(j) + k)

// byte is an alias for uint8
// no need to convert uint8 to byte because same
var (
    l byte  = 123
    m uint8 = 45
)
fmt.Println(l + m)

// int is an alias for int32 or int64, // dedpending on your mqchine's integer value
var (
    n int32 = 324
    o int   = 84529899
)
fmt.Println(int(n) + o)

// uint is an alias for uint32 or int64
var (
    p uint   = 999
    q uint64 = 9999
)
fmt.Println(p + uint(q))

// float operations do not produce an exact result after n decimals// like in most languages
myFloat := 1.000
myFloat2 := .999
fmt.Println(myFloat - myFloat2)

// arithmetic operations
fmt.Printf("%d + %d = %d \n", 25, 39, 25+39)
fmt.Printf("%d - %d = %d \n", 25, 39, 25-39)
fmt.Printf("%d * %d = %d \n", 25, 39, 25*39)
fmt.Printf("%d / %d = %v \n", 25, 39, 25/39)
fmt.Printf("%d %% %d = %v \n", 25, 39, 25%39)

// constants
const goldenRatio float64 = 1.6180327868852
fmt.Printf("The golden ration approximately %f \n", goldenRatio)
fmt.Printf("The ration truncated to the 3rd decimal is %.3f \n", goldenRatio)

// formatted printing for numeric types
fmt.Printf("decimal is %d \n", 99)
fmt.Printf("binary is %b \n", 99)
fmt.Printf("unicode reference is %c \n", 99)
fmt.Printf("hexadecimal is %x \n", 99)
fmt.Printf("scientific notation of goldenRatio is %e \n", goldenRatio)

}

String Types

package main

import “fmt”

func main() {
// zero-value for strings is an empty string “”
var str string
fmt.Println(""" + str + “”")

str = "This is a string."
fmt.Println(str)

str2 := "Another string."
fmt.Println(str2)

// raw string literalss with back ticks
// can be written on multiple lines and no escapes
str3 := `
    Raw string in the building.
    And another line.
`
fmt.Println(str3)

str4 := "Dunya nzuri = "
str5 := "美麗的世界"
str6 := str4 + str5
fmt.Println(str6)

// In Go, strings are immutable sequences of bytes
// you can access each byte
str7 := "mazoezi"
b1 := str7[0]
b2 := str7[1]
fmt.Println(str7, "\n\t", b1, "=", string(b1), b2, "=", string(b2))

// substrings
s1 := str7[0:2]
s2 := str7[2:4]
s3 := str7[:3]
s4 := str7[3:]
fmt.Printf("%s \t %s \t %s \t %s \n", s1, s2, s3, s4)

// length of string
fmt.Println(str7, " = ", len(str7), " characters")

// single character = rune -> numeric type, sane as int32
// can be converted to a string
var r rune 
// single qutoes
r = '✖'         // same as r = 10006
fmt.Println("This is a rune : ", r, " which in string = ", string(r))

}

If and For Statements

package main

import “fmt”

func main() {
a := 27

// no parentheses surrounding the condition
// the body of the if statement MUST be surrounded with {} // no matter what
// no truthy values
if a > 25 {
    fmt.Println("a is greater than 25")
} else {
    fmt.Println("a is less than 25")
}

b := 546

// if statement have block scope
if b == 546 {
    // c does not exist outside of the if
    c := 54
    fmt.Println(b + c)
}

// can declare a variable available ONLY in if and else block
if d := 44; b < 25 {
    fmt.Println("a is greater than 25", d)
} else {
    fmt.Println("a is less than 25", d)
}

// for loop, no parentheses around signature
e := 2
for index := 0; index < 10; index++ {
    if index+e == 2 {
        continue
    }
    if index > 8 {
        break
    }
    fmt.Println("index =", index)

}

// equivalent of while statement
f := 0
for f < 6 {
    fmt.Println("f =", f)
    // don't forget to have smth allowing to get out of the loop
    f++
}

// infinite loop
g := 0
for {
    fmt.Println("g =", g)
    g++
    // to stop it at some point
    if g > 30 {
        break
    }
}

// for range loop

h := "this is great!"
for k, v := range h {
    fmt.Println("offset (position) =",k,", value as rune =", v, ",value as string = ", string(v))
}

// logical operators
fmt.Printf("%t && %t is %t \n", true, false, true && false)
fmt.Printf("%t || %t is %t \n", true, false, true || false)
fmt.Printf("!%t is %t \n", true, !true) 

}

Functions

package main

import “fmt”

func main() {
addNumbers(353454, 99999)
addNumbers(353, 9999)
addNumbers(3554, 99)

a := addInts(99, 1)
fmt.Println("a = ", a)

a = addInts(9, 675)
fmt.Println("a = ", a)

div, remainder := divAndRemainder(57, 7)
fmt.Println(div, remainder)

// use underscore to ignore a returned value
div, _ = divAndRemainder(57, 7)
fmt.Println(div)

_, remainder = divAndRemainder(57, 7)
fmt.Println(remainder)

divAndRemainder(57, 7)

// in Go, all functions calls are done by value// (exceptions, see later)
// a copy of input argument variables is passed o the function
y := 5
arr := [2]int{45, 99}
s := "olo"
doubleFail(y, arr, s)
fmt.Println("outside doublefail", y, arr, s)

}

// where function is placed does not matter
// no overloading of function w/ different input parameters
func addNumbers(a int, b int) {
fmt.Println(a + b)
}

func addInts(c int, d int) int {
return c + d
}

// multiple returns
func divAndRemainder(e int, f int) (int, int) {
return e / f, e%f
}

func doubleFail(a int, arr [2]int, s string) {
a = a * 2
for index := 0; index < len(arr); index++ {
arr[index] *= 2
}
s = s + s
fmt.Println(“in doublefail”, a, arr, s)
}

Pointers

// pointers are used in C to simulate arrays and strings
package main

import “fmt”

// pointer as input parameter
func setTo10(pointerToInt *int) {
*pointerToInt = 10
}

func setTo10Fail(pointerToInt *int) {
fmt.Println("#setTo!(Fail pointer passed as argument =", pointerToInt)
// will not affect the original pointer because passed by value
pointerToInt = new(int)
fmt.Println("#setTo!(Fail reassignment =", pointerToInt)

// set the value in memory to 10
*pointerToInt = 10

}

func main() {
a := 10
// & = reference / pointer to variable “a”
// the value of b is the location where a is stored
b := &a
// c is a copy of “a” at a given time, // they are independent of each other after the first assignment
c := a
fmt.Println(a, b, *b, c)

a = 20
// to see the value inside the memory location use * // (de-reference the pointer and get to the value)
fmt.Println(a, b, *b, c)

// dereference the pointer and assign a value in memory
// therefore the value of "a" also changes
*b = 30
fmt.Println(a, b, *b, c)

c = 40
fmt.Println(a, b, *b, c)

// zero-value for a pointer is nil (absence of value)
var d *int
fmt.Println("value of d =", d)
// cannot read or write value of a nil pointer
// fmt.Println(*d)   // throws a panic

e := new(int)
// new keyword makes a pointer for the type
fmt.Println("pointer to e =", e)
// new also allocates memory, here to the zero-value forint type// therefore no panic
fmt.Println("value of e =", *e)

f := 20
fmt.Println("value of f =", f)
// we pass a pointer to f into that function
setTo10(&amp;f)
fmt.Println("value of f after setTo10 =", f)

g := 30
fmt.Println("pointer to g =", &amp;g)
fmt.Println("value of g =", g)
// on Go, variable in function calls are passed by VALUE
setTo10Fail(&amp;g)
fmt.Println("pointer to g after #setTo10Fail =", &amp;g)
// you CANNOT change the pointer of a variable passed
fmt.Println("value of g after #setTo10Fail =", g)

}

Arrays

package main

import “fmt”

func main() {
// zero-value of arrays is an array// of specified length of zero-values of the type inside the array
var myArrInt [4]int
fmt.Println(myArrInt)

myArrInt[0] = 12
myArrInt[1] = 23
myArrInt[2] = 34
myArrInt[3] = 45
fmt.Println(myArrInt)

// one-line array assihnement in a composite literal expression
// the length of the array is part of its type definition
myArrInt = [4]int{111, 222, 333, 444}
fmt.Println(myArrInt)

myArrStr := [4]string{"titi", "tooi", "tatu", "teti"}
fmt.Println(myArrStr)

// iterate over an array
for i, val := range myArrInt {
    fmt.Printf("At index %d = %d \n", i, val)
}

// slice of an array
myArrStr2 := myArrStr[:2]

// use _ to ignore the index variable
for _, val := range myArrStr2 {
    fmt.Println(val)
}
// use of arrays is limited, slices are more flexible

}

Slices and Maps

package main

import “fmt”

func main() {
/*
SLICE = growable sequence of values of a single specified type
the size is not part of the type definition
*/
// define a slice in a composite literal expression
myFiboSlice := []int{0, 1, 2, 3, 5, 8, 13}
fmt.Println(“myFiboSlice is”, myFiboSlice)

// create a slice from another slice = slice expression
myFiboSlice2 := myFiboSlice[1:4]
fmt.Println("myFiboSlice2 is", myFiboSlice2)

// carefully with subslices because// they point to the same location in memory as the original slice
myFiboSlice[2] = 00
fmt.Println("\n myFiboSlice is", myFiboSlice)
// slices are reference types, behave like pointers
fmt.Println("myFiboSlice2 after modifying myFiboSlice is", myFiboSlice2)

// zero-value for slice is nil slice (no value in slice)
titiSlice := []string{"titi_one", "titi_two", "titi_three"}
var totoSlice []string
fmt.Println("totoSlice is", totoSlice)
fmt.Println("length of totoSlice is", len(totoSlice))

// assigning slice to another slice makes them share same location// in memrory
totoSlice = titiSlice
fmt.Println("totoSlice is now", totoSlice)
titiSlice[0] = "titi_zero"
fmt.Println("after modifying titiSlice, totoSlice is now", totoSlice)

// this behavior also happens in functions
modifySlice(titiSlice)
fmt.Println("after modifying titiSlice in a function, totoSlice is now", totoSlice)

// define a slice filled with wero-values of the type specified
// last argument is the capacity of the underlying array
s1 := make([]int, 5, 20)

// copy a slice from another slice with the copy built-in function// "copy in slice s1 the elements of slice myFiboSlice
copy(s1, myFiboSlice) 
fmt.Println("\ns1 is", s1)

// append built-in function -&gt; returns a new slice
// increases the length of the slice
s2 := append(s1, 21, 34, 55)
fmt.Println("s2 is", s2)

// append a slice to another slice
s3 := []int{111, 222, 333}
// notice the ... after the s3 identier to spread the elements in it
s3 = append(s2, s3...)
fmt.Println("s3 is", s3)

// deleting element at offset 6 (7th) from slice (the easy way)
s3 = append(s3[:6], s3[7:]...)
fmt.Println("s3 is", s3)

// deleting from slice, the more involved way (see the function below)// it was tough to find a working algorithm !
s3 = deleteItemFromSliceAtIndex(s3, 3)
fmt.Println("s3 is", s3)

// slices are based on an underlying array // for which you can specify the capacity // (number of spots to allocate in memory)
// here the slice is initialized with 5 zero-value spots // but the underlying array has 100 spots in case we append.
// This allows to avoid to copy and create a new underlying array // every time we append more than the length of the slice
s4 := make([]int, 5, 100)
fmt.Println("s4 is", s4)
fmt.Println("length of s4 is", len(s4))
fmt.Println("capacity of s4 is", cap(s4))

// make a slice of bytes out of a string
hello := "李先生你好"
myByteSlice := []byte(hello)
fmt.Println("\nmyByteSlice is", myByteSlice)

myRuneSlice := []rune(hello)
fmt.Println("\nmyRuneSlice is", myRuneSlice)

// multidimensional slice
s5 := []int{84, 64, 44}
s6 := []int{42, 32, 22}
s7 := [][]int{s5, s6}
fmt.Println("\ns7 is", s7)

/********** MAPS ****************/

// associate value of single data type to value of another data type// collection of key / value pairs (key not restricted to a string)
// maps are unordered

myMap := make(map[string]string)
myMap["name"] = "GOTO"
myMap["firstname"] = "Florian"
myMap["occupation"] = "Software Engineer"
myMap["native_language"] = "French"
fmt.Printf("\n%v\n", myMap)

// access value in map
fmt.Printf("The name is %v\n", myMap["name"])

// if no value on a key return zero-value for the type of value
fmt.Printf("The age is %v\n", myMap["age"])

// make sure a key is in the map = comma ok idiom
// v = value associated w/ existing key
// ok = boolean is key in map
if v, ok := myMap["isBillionaire"]; ok {
    fmt.Println("isBillionaire in map =", v)
} else {
    // ok == false
    fmt.Println("isBillionaire in map =", ok)
}

// map literal declaration (composite literal expression)
worldMap := map[int]string{
    // every line must end with a comma
    1: "nimefurahi kukuona",
    2: "приємно бачити вас",
    3: "तुम्हें देखकर अच्छा लगा",
    4: "ስለተያየን ደስ ብሎኛል",
    5: "ดีใจที่ได้พบคุณ",
}

// iterate over a map - order of iteration is random
for keyInMap, valueInMap := range worldMap {
    fmt.Println(keyInMap, "=", valueInMap)
}

// delete value from map (built-in function)
delete(worldMap, 2)
fmt.Println("worldMap :", worldMap)

// same as slices, maps are passed by reference

// nil map
var tMap map[string]int
// writing to zero-valued map will make the program panic
// tMap["toto"] = 12345678
fmt.Println("tMap :", tMap)
fmt.Println("length of tMap :", len(tMap))

// delete an element in map
sport := map[string]string{"yoyo": "ok", "ping pong": "great"}
fmt.Println("sport :", sport)
delete(sport, "yoyo")
fmt.Println("sport :", sport)

// to make sure that you delete an existing pair in the map
langs := map[string]string{
    "ES6+":         "great",
    "Go":           "cool",
    "TypeScript":   "ok",
    "Python":       "over hyped but nice",
    "Bash":         "necessary",
    "HTML5":        "necessary",
    "CSS":          "necessary",
    "Elm":          "niche",
    "Java":         "no comments...",
    "Rust":         "to assess",
    "Web Assembly": "who knows",
}
fmt.Println("lang :", langs)
if _, ok := langs["assembly"]; ok {
    delete(langs, "assembly")
}
fmt.Println("lang :", langs)

}

func modifySlice(s []string) {
s[1] = “one”
fmt.Println("\n", s)
}

func deleteItemFromSliceAtIndex(s []int, index int) []int {
temp := make(map[int]int, len(s))
// convert slice to map
for i, v := range s {
if i == index {
continue
}
temp[i] = v
}

newSlice := make([]int, len(temp))

for i := 0; i &lt; len(temp); i++ {
    if i == index {
        // comma dot idiom = check if key in map
        value, ok := temp[i+1]

        // check that next index exists
        if ok &amp;&amp; i &lt;= len(temp) {
            newSlice[i] = value
            continue
        }
    }

    if i &gt; index {
        newSlice[i] = temp[i+1]
        continue
    }

    newSlice[i] = temp[i]
}

return newSlice

}

I won’t go into concurrency and the like (Goroutines, channels…) here which are more advanced topics that make Go apart from other languages.

Keep learning new things, never stops !


Learn More

Learn How To Code: Google’s Go (golang) Programming Language

Go: The Complete Developer’s Guide (Golang)

Build Realtime Apps | React Js, Golang & RethinkDB

The Complete Node.js Developer Course (3rd Edition)

Angular & NodeJS - The MEAN Stack Guide

The Complete JavaScript Course 2019: Build Real Projects!

Vue JS 2 - The Complete Guide (incl. Vue Router & Vuex)

Moving from NodeJS to Go

Authenticate a Node ES6 API with JSON Web Tokens

Full Stack Developers: Everything You Need to Know

Suggest:

Learn Startup - Build a successful business and change the world

Here are 380 Ivy League courses you can take online right now for free

Most Popular JavaScript Frameworks 2019 - I'm Programmer

Building a Video Blog with Gatsby and Markdown (MDX)

How to check if Checkbox is Checked or not using Plain JavaScript

10 Node Frameworks to Use in 2019