0% found this document useful (0 votes)
215 views38 pages

Golang Book

This document provides an overview of the basics of the Go programming language including its features, program structure, data types, syntax, and more. It covers Go's history and development, installation instructions, program structure with packages and files, basic syntax including comments, variables, constants, types, scope, basic data types, composite types like arrays and slices, and more. The document ends with a simple "Hello World" example program to demonstrate Go code.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
215 views38 pages

Golang Book

This document provides an overview of the basics of the Go programming language including its features, program structure, data types, syntax, and more. It covers Go's history and development, installation instructions, program structure with packages and files, basic syntax including comments, variables, constants, types, scope, basic data types, composite types like arrays and slices, and more. The document ends with a simple "Hello World" example program to demonstrate Go code.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 38

Basic Go Syntax

Learning Objectives
In this lesson, we’ll cover the basics of Go, its features, program structure, data types, syntax,
and more.
To put these concepts into practice, we’ll end session two with a simple coding exercise.

Prerequisites

● Basic understanding of ​computer programming terminologies


Session 1

What is Go?

“Go,​ also known as ​Golang​, is a statically typed, compiled programming language designed at
Google in 2007 by Robert Griesemer, Rob Pike, and Ken Thompson. Go is syntactically similar to C,
but with memory safety, garbage collection, structural typing, and communicating sequential
processes style concurrency.” ​- Wikipedia

Installation Guide

See ​instructions​ in the ​Golang​ website

Features of Go

● Imperative language
● Statically typed
● Syntax tokens similar to C (but less parentheses and no semicolons)
● Compiles to native code (no JVM)
● No classes, but uses structs with methods
● Interfaces
● No implementation inheritance. There's type embedding.
● Functions are first class citizens
● Functions can return multiple values
● Has closures
● Has pointers, but not pointer arithmetic
● Built-in concurrency primitives: Goroutines and Channels
Let’s go 
Hello world

Source code

// file main.go
package main

import (
"fmt"
)

func main() {
fmt.Println("Hello, World!")
}

Execute it

$ gofmt -s -w main.go // optional, rewrites code into the standard format


$ goimports -w main.go // optional, manages the insertion and removal of
import declarations as needed, install via command ​go get
golang.org/x/tools/cmd/goimports. It also format the code
$ go run main.go // execute it
Program Structure

A Go program is constructed by one or more source files, usually ending in ​.go​. Each
source file usually consists of the following parts:

● Import Packages
● Declaration for the following:
○ Packages
○ Constants
○ Variables
○ Types
○ Functions
○ Methods
Packages and Files

Declarations

A Go source file begins with a package declaration, which defines the package it
belongs to.

Go packages share the same purpose as libraries or modules in other languages.

A package in Go usually consists of one or multiple source files.

package name

// file demo.go
package demo

const (
Description = "Public constant" // public
description = "private constant" // private, visible to only its
own package
)

var (
Content string = "Public"
content string = "private"
)

func Sum() int { // ​exported


return 0
}

func sum() int { // ​unexported


return 0
}
Names

The names follow a simple rule: begins with a letter or an underscore and may have any
number of additional letters, digits, and underscores. Case matters: ​heapSort​ and
Heapsort​ are different names.

This naming convention applies for: ​functions, variables, constants,


types, statement labels​, and ​packages​.

If the name of ​var, const, type, func​ begins with an upper-case letter, it is
exported, which means that it is visible and accessible outside of its own package and
may be referred to by other parts of the program.

There are 25 ​reserved​ ​keywords:

break default func interface select

case defer go map struct

chan else goto package switch

const fallthrough if range type

continue for import return var


Comments

When adding comments, use the following syntax:

Line comment // this is a line comment

Block comments /* This is for block comments; it can have


many lines */
Variables

A ​var​ declaration creates a variable of a particular type, attaches a name to it, and sets
its initial value.

var ​name​ ​type​ = ​expression

When declaring variables, the ​type​ or ​expression​ must be indicated. Both cannot be
omitted. If the ​type​ is omitted, the ​type​ is determined by the initializer expression. If
the ​expression​ is omitted, the initial value is the ​zero value​ for the type.

var num int64 = 10

var zero int64

var ten = 10
Constants

A ​const​ declaration defines named values that syntactically look like variables, but
whose value is constant. This prevents accidental (or nefarious) changes during
program execution.

The underlying type of every constant is a basic type: ​boolean, string, or


number.

const ​name​ ​type​ = ​expression

const(
Pi = 3.14
Company = “Grab”
)

type Name string


const(
Grab Grab = “grab”
)
Type Declarations

The variable or expression type defines the characteristics of the values it takes on,
such as the size (number of bits or number of elements), how they are represented
internally, the intrinsic operations that can be performed on them, and the methods
associated with them.

type Age uint


type Student struct{
ID int
Name string
}

// group declaration
type (
Name string
User struct{
ID int
Name string
}
)
Scope

A declared identifier’s scope refers to the identifiable range of the identifier.

T​he scope definitions​:

● The scope of a predeclared/built-in identifier is the universe block.

● The scope of an import package’s identifier is the file block containing the
package import declaration.

● The scope of an identifier denoting a constant, type, variable, or function (but


not method) declared at package level is the package block.

● The scope of an identifier denoting a method receiver, function parameter, or


result variable is the corresponding function body (a local block).

● The scope of a constant or variable’s identifier declared inside a function begins


at the end of the constant or variable’s specification (or the end of the
declaration for a short declared variable) and ends at the innermost containing
block.

● The scope of a ​defined type​’s identifier declared inside a function begins at the
identifier in the type’s specification that ends at innermost containing block.

● The scope of an alias’ identifier declared inside a local block begins at the end
of the type declaration and ends at the innermost containing block.

● The scope of a label is the innermost function body block containing the label
declaration, but excludes all the anonymous functions’ bodies nested in the
containing function.

● Blank identifiers have no scope.


Basic Data Types

Here’s a list of the basic data types:

type sample

int int8 int16 int32 int64 -1 0 1 2

uint uint8 uint16 uint32 uint64 0 1 2

float32 float64 0 1.5

char ( alias of int8 ) ‘x’

rune ( alias of int32 )

string “Go” “走”

Complex64 complex128

Integers

See in ​Golang website

Floating point number

See in ​Golang website

Boolean

See in ​Golang website


Complex numbers

See in ​Golang website

Strings

A string is an immutable sequence of bytes.

Declarations

Strings are defined between two double quotes or two backquotes.

s := “Grab”
hello := `Welcome`

Lengths

The built-in len function returns the number of bytes in a string instead of the number of
characters in a string.

s := “Grab”
fmt.Println(len(s)) // 4

S := “Chào”
fmt.Println(len(s)) // 5
Count characters

The strings in Go are UTF-8 encoded by default. ​Go represents a character (code point) in
int32​ data type. A ​rune​ is Go terminology for a single Unicode code point.

func count(value string) int{


var total int
for range value{
total++
}
return total
}

S := “Chào”
fmt.Println(count(s)) // 4

Library

Here are some important standard library packages for working with strings:

● strings​ implements string searching, splitting, case conversions


● bytes​ has the same functionality as ​strings​ package but operates on ​[]byte​ slices
● strconv​ for converting strings to integers and float numbers
● unicode/utf8​ decodes from UTF-8-encoded strings and encodes to UTF-8-encoded
strings
● regexp​ implements regular expressions
● text/scanner​ is for scanning and tokenizing UTF-8-encoded text
● text/template​ is for generating larger strings from templates
● html/template​ has all the functionality of ​text/template​ but understands the structure of
HTML for HTML generation that is safe from code injection attacks
Composite Types

Arrays

An array is a fixed length sequence of a particular type. Arrays are rarely used in Go.

var a [3]int

var b [...]int{1, 2, 3}

fmt.Println(a[0], a[1], a[2]) // print 0 0 0

fmt.Println(len(a), len(b) // print 3 3

Slices

A slice is a variable length sequence of a particular type. A slice has three components:

● A pointer points to the first element of the array that is reachable through the slice
● The length is the number of slice elements, it can’t exceed the capacity ( ​len​ )
● The capacity is the number of elements between the start and the end of the underlying
array ( ​cap​ )

var s []int // len = 0, cap = 0

a := make([]int, 3, 10) // len = 3, cap = 10


Multiple slices can share the same underlying array and my refer to overlapping parts of that
array.

var arr = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

var x = arr[0:2] // len = 2, cap = 10


var y = arr[2:5] // len = 3, cap = 8

Append

The build-in ​append​ function appends items to slices.

var a []int
var b = []int{1, 2, 3}
a = append(a, 0) // a = [0]
a = append(a, b … ) // a = [0, 1, 2, 3]

Note: Since a slice contains a pointer to an array element, passing a slice to a function permits
the function to modify the underlying array elements.
Maps

A map is an unordered collection of key/value pairs in which all key are distinct. All of the keys
in a given map are of the same type.

● The key type must be comparable using ​==


● There are no restrictions on the value type

var m map[string]int
var a = map[string]interface{}{
“name”: “foo”,
“age” : 10,
}
x := map[string]struct{} {
“foo”: struct{}{},
“bar”: struct{}{},
}

for key, value := range a{


fmt.Println(key, value )
}

/* will print
name foo
age 10
*/

Structs

A struct is an aggregate data that groups together zero or more fields. Each field will have a
name and a data type for that name.

type Circle struct{


X int
Y int
Radius float64
}

var x Circle
x.X = 1
x.Y = 2
x.Radius = 10

var y = Circle { X: 1, Y: 1, Radius: 0.5 }

Anonymous structs

An anonymous struct is a struct without a name.

x := struct {
Name string
} {
Name: “Grab”
}

Composition and embedding

Go allows field definitions for a nameless type, such a field is called anonymous field. The field
type must be a named type or pointer to a named type. ​In effect, the outer struct type gains not
just the embedded type fields, but its methods too.

type Animal struct {


Name string
}

type Cat struct {


Animal
}

type Dog struct {


*Animal
}

var x Cat
var y = Cat{
Animal: Animal{
Name: "Foo",
},
}
var d = Dog{
Animal: &Animal{
Name: "Bar",
},
}
Functions

A function is a sequence of statements known as a unit, which can be called from anywhere
else in the program.

The function declaration has the following elements:

- A name
- A list of parameters, which specifies the names and types of the function’s parameters
- The return list specifies the names (optional) and types of the function’s returns. If the
name is specified, then it is declared as a local variable for the function.

Declaration

func name(parameter list) (return list) {

body

func sum(a, b int) int{


return a + b
}

func dump(value int) {


fmt.Println(value)
}

func get(url string) (io.Reader, error){


return nil, nil
}

func lowercase (value string ) (s string) {


s = strings.​ToLower(value)
return
}

Return values

A function can return more than one results.

You can name returned values that act as implicit local variables.

func parse(value string) (u *url.URL, err error){


u, err = url.Parse(value)
return
}

func read(filename content) ([]byte, error){


f, err := os.Open(filename)
if err != nil {
Return nil, err
}
data, err := ioutil.ReadAll(f)
if err != nil{
Return nil, err
}

return data, nil


}
First class

Functions are the ​first-class​ values in Go. It has types and can be assigned to variables or
passed to or returned from functions. A function value can be called like any other functions.

func sum(a, b int) int { return a + b }

var decrease = func(value int) int { return value - 1 }

func main() {
s := sum
total := s(1, 2)
fmt.Println(total)) // 3
fmt.Println(decrease(10)) // 9
}
Variadic functions

A variadic function can be called with varying numbers of arguments.

func sum(values ...int) int{

var total int

for _, value := range values{

total += value

return total

// usage

total := sum(1, 2, 3) // 6

total := sum() // 0
Defer ​statements

A defer statement is an ordinary function or method call prefixed by the keyword ​prefer. ​The
function and argument expressions are evaluated when the statement is executed, but the
actual call is deferred until the function that contains the defer statement has finished.

If a function has multiple defer statements, they are executed in reverse order.

func increase(value int) int{

defer func(v int) {

fmt.Println(“receive:”, v)

}(value)

return value++

const DEBUG = true

func decrease (value int) int{

If DEBUG {

defer func(v int) {

fmt.Println(“receive:”, v)

}(value)

return value--

func hello() {
defer fmt.Print(1)

defer fmt.Print(2)

defer fmt.Print(3)

// output: 321
Methods

A method is a function tied to a type, most commonly a struct.

Declarations

A method is declared with an ordinary function declaration variant in which an extra parameter
appears before the function name. The parameter attaches the function to that parameter type.

type Point struct{


X int
Y int
}

func (p Point) Distance(value Point) float64{


return math.Hypot(p.X-value.X, p.Y - value.Y)
}

func (p* Point) Reset() {


p.X = 0
p.Y = 0
}

// usage

a := Point( X: 1, Y: 1}
b := Point{ X: 4, Y: 5}
fmt.Println( a.Distance(b) ) // 5
a.Reset()
fmt.Println(a.X, a.Y) // 0, 0
Value vs pointer receiver

Method receiver can be either a value and a pointer. When calling a function, Go will make a
copy of each argument value. Ensure to use:

- Pointer receiver to update the receiver variable or type when it’s too large. Note that ​nill
is a valid receiver value.
- Value receiver when there are no side effects.

type Ints struct{


values []int
}

func (i *Ints) Sum() int{


if i == nil {
return 0
}
var total int
for _, value := range i.values{
total += value
}
return total
}
Interfaces

An interface describes a set of methods on a type. It is used to abstract behavior.

Interfaces can only contain methods, not data.

type Printer interface{


fmt.Print(w io.Writer)
}

type Int int

func (i Int) Print(w io.Writer){


fmt.Fprintf(w, “%d”, i)
}
Type switch

To determine underlying type from interface, we can use a type switch.

type Point struct {


X int
Y int
}

type Square struct {


TopLeft Point
BottomRight Point
}

func (s Square) Paint() {


// todo
}

type Painter interface{


Paint()
}

func typecheck(painter Painter) {


switch value := painter.(type) {
case Square:
fmt.Println(“Square”, value)
default :
fmt.Println(“Unknown”)
}
}

Empty interface

The empty interface is an interface with no method. Since every type conforms to
interface{}​, you can assign any value to a variable of ​interface{}​ type.

var x interface{}
x = 1
x = struct{}{}
x = Point{}
Type assertion

Type assertion allows you to check an empty interface value’s given type.

func check(value interface{}}{


num, ok := value.(int)
If ok {
fmt.Println(“Given value is a number”, num)
} else{
fmt.Println(“Given value is not a number”)
}
}
Control structures

If

If num > 0 {
return num
}

if f, err := os.Open(“grab.doc”); err != nil {


return nil, err
}

_, err := os.Create(“grab.doc”)
if err != nil {
// todo
} else if err = os.EOF {
// todo
} else {
// todo
}

For
The for syntax consists of three different forms, only one of which has semicolons:

// Like a C for
for init; condition; post { }

// Like a C while
for condition { }

// Like a C for(;;)
for { }

For example:

for i := 0; i <= 10; i++{


// todo
}
nums := []int{}
for index, num := range num{
// todo
}

m := map[string]int{}
for key, value := range m{
// todo
}

Switch

Switch statements provides multi-way execution

switch num{
case 1:
return “A”
case 2, 3, 4:
return “B”
case 5:
return “C”
}

switch {
case a < b:
return -1
case a > b:
return 1
default:
return 0
}

Go only runs the matched case. If you want to continue with the rest of the code execution, use
fallthrough.

n := 1
switch n {
case 1:
fmt.Println(“case 1”)
case 2:
fmt.Println(“case 2”)
}
// output
case 1

switch n {
case 1:
fmt.Println(“case 1”)
fallthrough
case 2:
fmt.Println(“case 2”)
}
// output
case 1
case 2

Goto
A goto statement transfers control to the statement with the corresponding label within the same
function.

func printAB(num int) {


if num%2 == 1 {
goto odd
}
fmt.Println("A")
return
odd:
fmt.Println("B")
}
Error handling

In Go, errors are values, just like strings and integers. Go handles failures by returning error
values. If a function or method returns an error, it should always be the last returned value.

func divide(a, b int) (int, error){


If b == 0{
return 0, errors.New(“invalid value”)
}
return a / b, nil
}

Error interface

In Go, the error type is a built-in interface with a single method ​Error() string.

Creation
You can create an error with the following approaches:
- errors.New
- fmt.Errorf
- Custom error type

var err error = errors.New(“not found”)

var err error = fmt.Errorf(“not found %d”, 1)

type MyError struct{


Message string
}

func (m MyError) Error() string {


return m.Message
}

var err error = MyError{Message: “Hello my first custom error”}


Panic and recover
Panic and recover are similar to exception handling in other languages like C#, Java, etc:
● panic​ is the equivalent of the ​throw error
● recover​ is the equivalent of the ​catch error

A ​panic​ halts normal execution flow and exits the current function, while a ​recover​ attempts
to recover from a panic. The recover statement must appear directly within the deferred function
enclosure.

func get(url string) {


defer func() {
If err := recover(); err != nil {
fmt.Println(“recover with err”, err)
}
}()
u, err := url.Parse()
if err != nil {
panic(err)
}
// todo
}
Exercises

- Effective Go

- Wiki

- Go Concurrency Patterns: Context

- Go Concurrency Patterns: Pipelines and cancellation

- Profiling Go Programs
Session 2
Write a simple REPL program (​Read–Eval–Print–Loop).

Take a formula from a user then print out the result. The formula must be in this format:

<first number> <arithmetic: + - * / > <second number>

Example:

> 1 + 2
1 + 2 = 3
> 2 * 10
2 * 10 = 20
> 100 / 10
100 / 10 = 10

You might also like