Day 2: Built-in Features

Posted on

This tutorial consists of a number of example go programs demonstrating each feature. It is recommended to try some of them on the Go playground or on your local machine.

Constants are declared using the const keyword. They can be declared with a data type but it’s not common. The “Hello World” string can be stored in a constant and printed.

package main

func main() {
	const hello = "Hello World"
	println(hello)
}

Variables

Variables can be declared using the var keyword. The “Hello World” string can be stored in a variable before printing.

package main

func main() {
	var hello string
	hello = "Hello World"

	// hello := "Hello World"
	// Can be used to declare and assign
	// at the same time. Check note below.

	println(hello)
}

The first 2 lines in the function can be shortened with the “:=” operator. This will attempt to identify the type form the value and use it. In most cases this will work as expected but when using numbers, it will always use int for integers and float64 for floating point numbers. When writing Go programs, the := operator is preferred more than declaring with var and assigning later.

Please note that all variables created must be used in the program otherwise it’ll give an error when running/compiling. In some cases the “_” can be used in place of a variable.

Go has many more data types which can be read from the go specification. The go spec is shorter than most others and also very easy to read and understand.

Functions

Functions can be defined in Go using the func keyword. The hello world program can be written using a sayHello function.

package main

func main() {
	sayHello()
}

func sayHello() {
	println("Hello World")
}

Go functions can also get a number of arguments and use them.

package main

func main() {
	sayHello("John", "Doe")
}

// sayHello(fname string, lname string)
// is also valid and does the same thing
func sayHello(fname, lname string) {
	println("Hello " + fname + " " + lname)
}

Go functions can also return multiple arguments.

package main

func main() {
	fname, lname := getName()
	sayHello(fname, lname)
}

func getName() (string, string) {
	return "John", "Doe"
}

func sayHello(fname, lname string) {
	println("Hello " + fname + " " + lname)
}

Go functions can be used as values. They can be stored in variables, passed as arguments and returned from other functions.

package main

func main() {
	greet := getGreeter("Hi")
	greet("John Doe")
}

func getGreeter(prefix string) func(name string) {
	fn := func(name string) {
		println(prefix + " " + name)
	}
	return fn
}

Above example also demonstrates why is most commonly known as a closure. The function created inside getGreeter captures surrounding variables (in this example, the prefix variable) and remembers it when it’s used later.

Control Statements

Go only has a few statements to control program flow. They are if, switch, for, break, continue and goto. Go also has a select statement which is best explained after getting used to go-routines and basics of concurrent programming in go.

If

In Go control statements do not use parentheses.

package main

func main() {
	user := "Goku"

	if user == "Goku" {
		println("Hello Admin")
	}
}

If conditions may also have an else block.

package main

func main() {
	user := "Nappa"

	if user == "Goku" {
		println("Hello Admin")
	} else {
		println("Hello Guest")
	}
}

Go also supports else-if blocks. In some cases, a switch may be more appropriate than long if-else ladders.

package main

func main() {
	user := "Gohan"

	if user == "Goku" {
		println("Hello Admin")
	} else if user == "Gohan" {
		println("Hello User")
	} else {
		println("Hello Guest")
	}
}

switch

Above example can be written using a switch statement. A switch can be used with strings, integers and other types.

package main

func main() {
	user := "Gohan"

	switch user {
	case "Goku":
		println("Hello Admin")
	case "Gohan":
		println("Hello User")
	default:
		println("Hello Guest")
	}
}

The switch can be written in another format which is useful for more complex situations.

package main

func main() {
	user := "Goku"
	pass := "Pass"

	switch {
	case user == "Goku" && pass == "[email protected]$Z":
		println("Login Success")
	case user == "Goku":
		println("Incorrect Password")
	default:
		println("User Not Found")
	}
}

for

Go only has for loops but it has a few forms. For loops can be used in many ways depending on the situation. The first form is the infinite loop. The break keyword can be used to exit the loop when necessary.

package main

func main() {
	for {
		println("Loop")
	}
}

The second form is similar to the while loop in most languages.

package main

func main() {
	i := 0

	for i < 5 {
		i++
		println("Loop")
	}
}

Above loop can be written using the more common for loop like form.

package main

func main() {
	for i := 0; i < 5; i++ {
		println("Loop")
	}
}

There are 2 more special cases which is explained under Slices and Maps.

Data Structures

Go only has a few data structures built into the language but they are flexible enough to more complex ones on top of them.

Slices

Go arrays are fixed length therefore not easy to handle. Therefore, go programmers often use slices to store series of data. A slice can be created using the make keyword. In this example the Println function inside the fmt package is used. fmt.Println can print more data types than println. Packages will be explained more in a future tutorial.

package main

import "fmt"

func main() {
	sz := 3 // slice size
	t3s := make([]string, sz)
	t3s[0] = "Krillin"
	t3s[1] = "Gohan"
	t3s[2] = "Dende"
	fmt.Println(t3s)
}

Slices can also be created with an initial set of elements. Additional items can be added to a slice using the append function. Please note that the array used for the slice may or may not change which depends on the slice’s capacity (array size).

package main

import "fmt"

func main() {
	t3s := []string{"Krillin", "Gohan", "Dende"}
	t4s := append(t3s, "Vegeta")
	fmt.Println(t3s, t4s)
}

The for loop has a special form to iterate over a slice.

package main

import "fmt"

func main() {
	t3s := []string{"Krillin", "Gohan", "Dende"}
	t4s := make([]string, 4)

	for i, name := range t3s {
		t4s[i] = name
	}

	t4s[3] = "Vegeta"
	fmt.Println(t3s, t4s)
}

The copy function can be used to copy data form one slice to another.

package main

import "fmt"

func main() {
	t4s := []string{"Krillin", "Gohan", "Dende", "Vegeta"}
	t3s := make([]string, 3)
	copy(t3s, t4s)

	fmt.Println(t3s, t4s)
}

A slice can be made from another slice. Both slices still use the same array. Therefore any changes made to one slice will reflect on the other.

package main

import "fmt"

func main() {
	t4s := []string{"Krillin", "Gohan", "Dende", "Vegeta"}
	t3s := t4s[0:3]
	fmt.Println(t3s, t4s)

	t3s[2] = "Little Green"
	fmt.Println(t3s, t4s)
}

To learn more about how slices work, read go slice usage and internals on golang blog.

Maps

Go map keys can be strings, integers, floats, structs or pointers to data types. This can be useful for mapping one value to another with many data types. The same make keyword can be used to create an empty map.

package main

import "fmt"

func main() {
	t3s := make(map[string]string)
	t3s["Krillin"] = "Human"
	t3s["Gohan"] = "Saiyan"
	t3s["Dende"] = "Namekian"
	fmt.Println(t3s)
}

A map can be created with an initial set of items. Unlike slices, maps are copied if assigned to a new variable.

package main

import "fmt"

func main() {
	t3s := map[string]string{
		"Krillin": "Human",
		"Gohan": "Saiyan",
		"Dende": "Namekian",
	}
	
	t4s := t3s
	t4s["Vegeta"] = "Saiyan"

	fmt.Println(t3s, t4s)
}

For loop has a special form for maps to iterate over keys and values. The order keys are accessed is randomized by Go to make sure that developers do not depend on it accidentally.

package main

func main() {
	t3s := map[string]string{
		"Krillin": "Human",
		"Gohan":   "Saiyan",
		"Dende":   "Namekian",
	}

	for name, race := range t3s {
		println(name + " is a " + race)
	}
}

Structs

Go structs are a collection of variables with one or more data types.

package main

import "fmt"

func main() {
	type member struct {
		name string
		race string
	}
	
	krillin := member{}
	krillin.name = "Krillin"
	krillin.race = "Human"

	gohan := member{
		name: "Gohan",
		race: "Saiyan",
	}

	fmt.Println(krillin, gohan)
}

Structs may also have methods which makes it similar to classes in OOP languages. To add methods to structs, they must be declared outside the main function.

package main

type member struct {
	name string
	race string
}

func (m member) intro() {
	println("Hi, I'm " + m.name)
}

func main() {
	krillin := member{
		name: "Krillin",
		race: "Human",
	}

	krillin.intro()
}

What’s Next ?

This tutorial only covers the most common parts of golang built-ins. To read more the best place is the golang spec. It’s also the best place to look when there’s a question regarding how go works.