Learn Go programming
Learn Go programming
Satish Talim
Buy on Leanpub

Table of Contents

Preface

Who is the eBook for?

These are the study notes, in eBook form, I made when I learned Go programming and is an introduction to the Go language. The intended audience are people who are familiar with programming and know some programming language. This does not teach you how to program, rather it teaches you how to use Go.

What will you learn?

In the end, you will understand and know the basics of the Go language.

Using code examples

All of the code in this eBook can be used pretty much anywhere and anyway you please.

Errata

Although I have taken every care to ensure the accuracy of the content of this eBook, mistakes do happen. If you find a mistake in this eBook — maybe a mistake in the text or the code — I would be grateful if you would report this to me. By doing so, you can save other readers from frustration and help me improve subsequent versions of this eBook. If you find any errata, please report them by sending me an email.

Acknowledgements

I have made extensive references to the following:

I’d like to thank the Go community who have written excellent articles, blog posts on Go. I have referred to many such articles and blog posts, while I learned Go, and given them due credit in this eBook.

There are a good number of people who deserve thanks for their help and support they provided, either while or before this eBook was written, and there are still others whose help will come after the eBook is released. For help with proof reading, checking exercises and text improvements, I would like to thank Anders Persson7, Basant Singh8, Christian Hujer, Gunnar Aasen, Jose Carlos Monteiro9, Kevin Lozandier10, Kiran Mysore11, Kirit Ayya12, Marcelo Magallon13, Nilesh Govindrajan14, Peggy Li15, Prathamesh Sonpatki16, Shawn Milochik, Valindo Godinho17 and Victor Goff18.

The Gopher character is based on the Go mascot designed by Renée French19 and copyrighted under the Creative Commons Attribution 3.0 license.

How to contact me?

I can be reached via e-mail at satish.talim@gmail.com. Please contact me if you have any questions, comments, kudos or criticism on the eBook. Constructive criticism is definitely appreciated; I want this eBook to get better through your feedback.

Thanks

Thanks for downloading and checking out this eBook. As part of the lean publishing philosophy, you’ll be able to interact with me as the eBook is completed. I’ll be able to change things, reorganize parts, and generally make a better eBook. I hope you enjoy.

  1. https://golang.org/doc/code.html
  2. https://tour.golang.org/welcome/1
  3. https://golang.org/ref/spec
  4. https://golang.org/doc/effective_go.html
  5. http://golang.org/doc/faq#unused_variables_and_imports
  6. http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/
  7. https://twitter.com/uandersp
  8. https://twitter.com/SinghBasant
  9. https://github.com/straider
  10. https://github.com/lozandier
  11. https://twitter.com/techgravity
  12. https://twitter.com/kirit_ayya
  13. https://github.com/mem
  14. https://twitter.com/nileshgr
  15. https://twitter.com/_peggyli
  16. https://twitter.com/_cha1tanya
  17. https://twitter.com/Valindogodinho
  18. https://twitter.com/kotp
  19. http://reneefrench.blogspot.in/

How to use this eBook

With the help of this eBook, you should:

  • Go through each exercise.
  • Type in each sample exactly.
  • Make it run.

If you go through this eBook, and do each exercise for one or two hours a night, you will have a good foundation for moving onto another book about Go to continue your studies. This eBook won’t turn you into a Go expert overnight, but it will get you started on the path to learning how to code in Go.

Remember:

  • Typing the code samples and getting them to run will help you learn the names of the symbols, get familiar with typing them, and get you reading the language.
  • You must pay attention to the tiniest details of your work or you will miss important elements of what you create. By going through this eBook, and copying each example exactly, you will be training your brain to focus on the details of what you are doing, as you are doing it.
  • While you do these exercises, typing each one in, you will be making mistakes. It’s inevitable; even seasoned programmers would make a few. Your job is to compare what you have written to what’s required, and fix all the differences. By doing so, you will train yourself to notice mistakes, bugs, and other problems.
  • You must type each of these exercises in, manually. If you copy and paste, you might as well not even do them. The point of these exercises is to train your hands, your brain, and your mind in how to read, write, and see code. If you copy-paste, you are cheating yourself out of the effectiveness of the lessons.

I know that to get good at anything you have to practice every day, even if it’s difficult. Keep trying and eventually it’ll be easier and fun.

If you break the problem down into small exercises and lessons, and do them every day, you can learn to do almost anything. If you focus on slowly improving and enjoying the learning process, then you will benefit no matter how good you are at it.

Remember whatever your reason for wanting to quit, don’t. Victor Goff and I are available on the slack channel1 to help you in the learning process.

  1. https://docs.google.com/forms/d/1WXO68p3gH4b-4S3dOS_MUbvoe7uaRNT9tii1syTznYA/viewform

1. Introduction

1.1 What is Go?

From the website1 -

Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.

Go comes with a great standard library and an enthusiastic community.

1.2 Go Recent History

The history of the language before its first release, back to 2007, is covered in the language’s FAQ2.

The mascot and logo were designed by Renée French3. The logo and mascot are covered by the Creative Commons Attribution 3.0 license.

The current version of Go is 1.5. Development will continue on Go itself, but the focus will be on performance, reliability, portability and the addition of new functionality such as improved support for internationalization.

1.3 Go Authors

Go was initially developed at Google in 2007 by Robert Griesemer4, Rob Pike5 and Ken Thompson6.

Go became a public open source project on November 10, 2009. Many people from the community have contributed ideas, discussions, and code.

1.4 Why Go?

Very briefly:

  • Compiled, instead of interpreted or byte-coded for a virtual machine
  • Fast, to compile and to execute
  • Safe because it’s Statically Typed, instead of dynamically typed
  • C-like Syntax, but much cleaner and simpler (less noise, less verbose), with a self-imposed convention for its Coding Style
  • Type Inference and Postfix Types
  • Garbage Collector
  • UTF-8 encoding mode, by default
  • Concurrency, with Channels and GoRoutines
  • Open Source
  1. https://golang.org/
  2. https://golang.org/doc/faq#history
  3. http://reneefrench.blogspot.in/
  4. http://en.wikipedia.org/wiki/Robert_Griesemer
  5. http://en.wikipedia.org/wiki/Rob_Pike
  6. http://en.wikipedia.org/wiki/Ken_Thompson

2. Learn Go programming

This eBook is an introduction to the Go language. The intended audience are people who are familiar with programming and know some programming language. This eBook does not teach you how to program, rather it teaches you how to use Go.

We shall be using the Go Playground1 to write and run most of the programs in this eBook.

I have purposely left the details of installing Go on your local computer and its various settings in Appendix A, as I first want you to get your hands wet with writing Go code!

There are limitations to the programs that can be run in the playground, which please be aware.

As such, there are certain programs in the eBook that will not run in the Go Playground. I shall tell you which programs won’t run.

Once the Go Playground loads up, clear whatever is written on the screen and type our first program:

Program: hello_world.go
1 package main
2 
3 import "fmt"
4 
5 func main() {
6 	fmt.Printf("Hello World")
7 }

Click on the Run button and you will see “Hello World” at the bottom of the screen.

Let’s quickly understand the above program:

  • Go programs are organized as packages.
  • The import statement allows you to use external code. The fmt package, in this case, which is provided by the standard library allows you to format and print data.
  • The main() function is what gets executed when you run your application - just like in C.

Let’s look at another bigger program in more detail:

Program: hello.go
 1 // Single line comment. Line comments start with the
 2 // character sequence // and stop at the end of the
 3 // line. A line comment acts like a newline.
 4 // Comments do not nest.
 5 
 6 /*
 7 Multi-
 8  line comment
 9 */
10 
11 /*
12 Package main.
13 All Go files start with package <something>.
14 package main is required for a standalone executable.
15 */
16 package main
17 
18 import "fmt"
19 
20 func main() {
21 	// Multiple statements separated by ;
22 	fmt.Printf("Hello "); fmt.Printf("World\n")
23 
24 	// Single statement then ; not needed
25 	fmt.Printf("Learning Go\n")
26 }

Once the Go Playground loads up, clear whatever is written on the screen and type out the above program.

Click on the Run button and check the output at the bottom of the screen.

Let’s understand this program:

2.1 Comments

Go provides:

  • /* */ are block comments. Block comments appear mostly as package comments, but are useful within an expression or to disable many lines of code.
  • Line comments start with the // character sequence and stop at the end of the line.
  • A line comment acts like a newline.
  • Comments do not nest.

Line comments are the norm.

2.2 Statements

The Go code is structured in statements. A statement doesn’t need to end with a ;. The Go compiler automatically inserts semicolons at the end of statements. However if multiple statements are written on one line (a practice which is not encouraged for readability reasons), they must be separated by ;.

For more information, please read “Semicolons” in a later chapter.

2.3 Identifiers

Identifiers name program entities such as variables and types.

  • An identifier is a sequence of one or more letters and digits.
  • The first character in an identifier must be a letter.
  • Identifiers are case-sensitive.

2.3.1 Blank identifier

The _ itself is a special identifier, called the blank identifier. It can be used in declarations or variable assignments like any other identifier (and any type can be assigned to it), but its value is discarded, so it cannot be used anymore in the code that follows.

2.3.2 Pre-declared identifiers

The following identifiers are implicitly declared:

Types bool, byte, complex64, complex128, error, float32,
  float64, int, int8, int16, int32, int64, rune, string,
  uint, uint8, uint16, uint32, uint64, uintptr
Constants true, false, iota
Null or no value nil
Functions append, cap, close, complex, copy, delete, imag, len,
  make, new, panic, print, println, real, recover

2.4 Keywords

This is the set of 25 keywords5 or reserved words and may not be used as identifiers.

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

2.5 package

  • All Go files start with package <something>.
  • In Go, package is always first, then import, then everything else.
  • package main is required for a standalone executable..
  • Every package should have a package comment, a block comment preceding the package clause.
  • The package comment should introduce the package and provide information relevant to the package as a whole.
  • Package comments should begin with the name of the thing being described and end in a period.
  • By convention, packages are given lower case, single-word names; there should be no need for underscores or mixedCaps.
  • Go’s convention is that the package name is the last element of the import path: the package imported as “crypto/rot13” should be named rot13.

2.6 import

  • import declaration declares library packages referenced in this file.
  • The package names are enclosed within "".
  • Apart from package main we are also using the fmt package.
  • A Go program is created by linking together a set of packages through the import keyword.
  • import "fmt" tells Go that this program needs (functions, or other elements, from) the package fmt6, which implements functionality for formatted IO.
  • import loads the public declarations from the compiled package, it does not insert the source code.
  • The Go installation contains a number of ready-to-use packages, which form the standard library. The entire standard library is documented, with examples, at http://golang.org/pkg/7.

If you are importing a single package then you write it like:

import "fmt"

If multiple packages are needed, they can each be imported by a separate statement:

1 import (
2         "fmt"
3         "os"
4 )

Only apply this when there is more than one entry; in that case it is also clearer to list the package names in alphabetical order.

Note: importing a package which is not used in the rest of the code is a build-error (for example: imported and not used: os).

imports10 are organized in groups, with blank lines between them. The standard library packages are in the first group. For example:

 1 package main
 2 
 3 import (
 4         "fmt"
 5         "hash/adler32"
 6         "os"
 7 
 8         "appengine/user"
 9         "appengine/foo"
10 
11         "code.google.com/p/x/y"
12         "github.com/foo/bar"
13 )

The above is a convention.

  • After importing a package, you can refer to the names it exports.
  • In Go, a name is exported if it begins with a capital letter. Foo is an exported name, as is FOO. The name foo is not exported. A concrete example is in our use of fmt.Println, note the Println with “P” not “p”.
  • In Go, the use of the words public and private is really not accurate. It is more accurate to say an identifier is exported or not exported from a package.
  • When an identifier is exported from a package, it means the identifier can be directly accessed from any other package in the code base.
  • When an identifier is not exported from a package, it can’t be directly accessed from any other package.

After the import statement, zero or more constants (const), variables (var), and types (type) can be declared; these are global (have package scope) and are known to all functions in the code, and they are followed by one or more functions (func).

2.6.1 Aliasing of imports

Go allows the aliasing of imports.

1 import tpl "text/template"
2 txt, err := tpl.New("test").Parse("Hello {{.Name}}")`

The code tpl "text/template" imports the text/template package under the name tpl.

Then the application can call functions in text/templete under the alias name, as shown above.

Aliases are a great (and necessary) feature of Go package management. But don’t go overboard. Conventionally, aliases are only used when necessary (such as when package names would otherwise collide). Code is more readable without unnecessary aliases.

2.6.2 Removing explicit package reference

We might choose to simplify matters a little by importing the fmt namespace into the namespace of the current source file, which requires we change our import statement.

import . "fmt"

This consequently allows the explicit package reference to be removed from the Println() function call.

Println("hello world")

1 package main
2 
3 import . "fmt"
4 
5 func main() {
6         Println("hello world")
7 }
Program: what_error.go
1 package main
2 
3 import "fmt"
4 import "os"
5 
6 func main() 
7 {
8 	fmt.println("Hello, world.")
9 }

Please use this link13 to run the program.

2.7 functions

  • func main() { is a function definition. main is special. It is the entry point for the executable program.
  • The requirements for the compiler to produce an executable are belonging to package main and declaring the main() function. This function receives no inputs and returns no result, it’s more like a “procedure” in some other languages.
  • Thus main has no parameters and no return type.
  • Go uses brace brackets. The first { must be on the same line as the func-declaration: this is imposed by the compiler. The last } is positioned after the function-code in the column beneath function.
  • fmt.Printf("") here we call a function Printf from the package fmt to print a string to the screen.
  • In Go, we use a dot notation to access the function Printf of the package fmt.

For more information on functions, please read “More on Functions” in a later chapter.

2.8 String literal

  • Interpreted string literals are UTF-8 characters between double quotes "" and may contain non-ASCII characters.
  • Once assigned to a variable the string can not be changed: strings in Go are immutable.

For more information on strings, please read “More on Strings” in a later chapter.

Go source code is Unicode text encoded in UTF-8.

Go programs are made of keywords, constants, variables, operators, types and functions.

2.9 Numbers

Go has several different types to represent numbers. Generally, we split numbers into two different kinds: integers and floating-point numbers.

2.9.1 Integers

Integers – like their mathematical counterpart – are numbers without a decimal component (-3, -2, -1, 0, 1,).

Our system is made up of 10 different digits. Once we’ve exhausted our available digits we represent larger numbers by using 2 (then 3, 4, 5, …) digits put next to each other. For example the number after 9 is 10, the number after 99 is 100 and so on. Computers do the same, but they only have 2 digits instead of 10. So counting looks like this: 0, 1, 10, 11, 100, 101, 110, 111 and so on. The other difference between the number system we use and the one computers use is that all of the integer types have a definite size. They only have room for a certain number of digits. So a 4 bit integer might look like this: 0000, 0001, 0010, 0011, 0100. Eventually we run out of space and most computers just wrap around to the beginning (which can result in some very strange behavior).

Go’s integer types are:

uint8, uint16, uint32, uint64, int8, int16, int32 and int64.

8, 16, 32 and 64 tell us how many bits each of the types use. uint means “unsigned integer” while int means “signed integer”. Unsigned integers only contain positive numbers (or zero). In addition there two alias types: byte which is the same as uint8 and rune which is the same as int32. Bytes are an extremely common unit of measurement used on computers (1 byte = 8 bits, 1024 bytes = 1 kilobyte, 1024 kilobytes = 1 megabyte, …) and therefore Go’s byte data type is often used in the definition of other types.

There are also 3 machine dependent integer types:

uint, int and uintptr.

They are machine dependent because their size depends on the type of architecture you are using.

Generally, if you are working with integers you should just use the int type.

2.9.2 Floating Point Numbers

Floating point numbers are numbers that contain a decimal component (real numbers eg. 1.234, 123.4, 0.00001234, 12340000.0). Their actual representation on a computer is fairly complicated and not really necessary to know in order to know how to use them.

We need only to keep the following in mind:

  • Floating point numbers are inexact. Occasionally, it is not possible to accurately calculate a number. For example computing 1.01 - 0.99 results in 0.020000000000000018 – A number extremely close to what we would expect, but not exactly the same. We can, of course, represent 0.02 with no difficulty.
  • Like integers, floating point numbers have a certain size (32 bit or 64 bit). Using a larger sized floating point number increases it’s precision (how many digits it can represent).
  • There are no constants denoting the IEEE-754 infinity and not-a-number values, but the math14 package’s Inf15, NaN16, IsInf17, and IsNaN18 functions return and test for those values at run time.

Go has two floating point types: float32 and float64 (also often referred to as single precision and double precision respectively) as well as two additional types for representing complex numbers (numbers with imaginary parts): complex64 and complex128.

Floating point precision is finite and you should always be very cautious when making comparisons on real numbers.

Generally, we should stick with float64 when working with floating point numbers.

Reference: The above write-up on Integers and Floating Point Numbers has been referred from the excellent eBook “An Introduction to Programming in Go19” by Caleb Doxsey.

Later on do read up on the big package.

2.9.3 Some default values

Type Initialized Value
Boolean false
Integer 0
Floating Point 0.0
String "" (empty string)

Note: When memory is allocated to store a value, either through a declaration or a call of make or new, and no explicit initialization is provided, the memory is given a default initialization. Each element of such a value is set to the zero value for its type: false for booleans, 0 for integers, 0.0 for floats, “” for strings, and nil for pointers, functions, interfaces, slices, channels, and maps.

2.10 Console output

2.10.1 Print and Println

The function Print print formats using the default formats for its operands and writes to standard output. Spaces are added between operands when neither is a string.

The function Println formats using the default formats for its operands and writes to standard output. Spaces are always added between operands and a newline is appended.

If you have Go installed on your local machine, then you can read the documentation of any of these functions. Example:

godoc fmt Println

2.10.2 Formatting using Printf

Function Printf from the package fmt use the following format verbs:

General %v the value in a default format
Boolean %t the word true or false
Integer %d base 10
Floating-point and complex %f decimal point but no exponent, e.g. 123.456
  %e scientific notation, e.g. -1234.456e+78
  %g %e for large exponents, %f otherwise
String %s string

The default value for %v is:

bool %t
int, int8 etc. %d
uint, uint8 etc. %d
float32, complex64, etc. %g
string %s

Please refer to fmt.Printf format reference - cheat sheet20

Let’s look at an example.

Program: format.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6         // Formatting booleans
 7         fmt.Printf("%v\n", false) 
 8         fmt.Printf("%t\n", true)
 9 
10         // Formatting integers
11         fmt.Printf("%v\n", 987)
12         fmt.Printf("%d\n", 345)
13 
14         // Formatting floats
15         fmt.Printf("%v\n", 987123456.987345123432)
16         fmt.Printf("%f\n", 987123456.987345123432)
17         // Use %g for large exponents 
18         fmt.Printf("%g\n", 987123456.987345123432)
19 
20         // When formatting numbers you will often 
21         // want to control the width and precision 
22         // of the resulting figure. To specify the 
23         // width of an integer, use a number after 
24         // the % in the verb. By default the result 
25         // will be right-justified and padded with 
26         // spaces.
27         fmt.Printf("|%6d|%6d|\n", 23, 987)
28 
29         // You can also specify the width of printed
30         // floats, though usually you'll also want to
31         // restrict the decimal precision at the same
32         // time with the width.precision syntax.
33         fmt.Printf("|%6.2f|%6.2f|\n", 3.2, 4.37)
34 
35         // To left-justify, use the - flag.
36         fmt.Printf("|%-6.2f|%-6.2f|\n", 3.2, 4.37)
37 
38         // So far we’ve seen Printf, which prints 
39         // the formatted string to os.Stdout. 
40         // Sprintf formats and returns a string 
41         // without printing it anywhere.
42         s := fmt.Sprintf("a %s", "string")
43         fmt.Println(s)
44         
45         fmt.Println(2001,3456)
46         fmt.Print(20,30)
47 }

Once the Go Playground loads up, clear whatever is written on the screen and type out the above program.

Click on the Run button and check the output at the bottom of the screen.

false
true
987
345
9.871234569873451e+08
987123456.987345
9.871234569873451e+08
|    23|   987|
|  3.20|  4.37|
|3.20  |4.37  |
a string
2001 3456
20 30

2.11 Console input

The functions Scan, Scanf and Scanln from the fmt package read from os.Stdin.

Scan scans text read from standard input, storing successive space-separated values into successive arguments. Newlines count as space. It returns the number of items successfully scanned.

Scanf scans text read from standard input, storing successive space-separated values into successive arguments as determined by the format. It returns the number of items successfully scanned. Scanf parses the arguments according to a format string, analogous to that of Printf with certain restrictions.

Scanln is similar to Scan, but stops scanning at a newline and after the final item there must be a newline or EOF.

Write the following program and store it in the same folder where you had stored hello.go:

Program: ci.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6         var username string
 7 
 8         fmt.Println("Enter Username: ")
 9         fmt.Scanf("%s", &username)
10 
11         fmt.Println("Username:", username)
12 }

For Windows users, use fmt.Scanf("%s\n", &username) instead of fmt.Scanf("%s", &username).

Run the program.

We shall learn about var and the & operator in later chapters.

2.12 Command-line arguments - Args

When we invoke a command on the terminal it’s possible to pass the command arguments.

In the command go run hello.go, run and hello.go are arguments to the go command.

In the package os we have a variable Args: var Args []string

Args hold the command-line arguments, starting with the program name. os.Args provides access to raw command-line arguments. Note that the first value in this slice is the path to the program, and os.Args[1:] holds the arguments to the program.

Note: We talk about slices in a later chapter.

Write the program cmd_line_args.go as follows and store it in the same folder where you had stored hello.go:

Program: cmd_line_args.go
1 package main
2 
3 import "fmt"
4 import "os"
5 
6 func main() {
7         //You can get individual args with normal indexing
8         fmt.Println(os.Args[1], os.Args[2], os.Args[3], os.Args[4])
9 }

Run this program, as follows:

go run cmd_line_args.go a1 a2 a3 a4

The output you will see is something like this:

a1 a2 a3 a4

2.13 Solutions

Exercise 1 Reasons21.

  1. https://play.golang.org/
  2. http://play.golang.org/p/sOqjtiXkRF
  3. https://play.golang.org/
  4. http://golang.org/ref/spec#Bootstrapping
  5. http://golang.org/ref/spec#Keywords
  6. http://golang.org/pkg/fmt/
  7. http://golang.org/pkg/
  8. https://godoc.org/golang.org/x/tools/cmd/goimports
  9. http://golang.org/doc/faq#unused_variables_and_imports
  10. https://github.com/golang/go/wiki/CodeReviewComments#imports
  11. https://golang.org/doc/go1compat
  12. https://golang.org/doc/go1compat
  13. http://play.golang.org/p/9vq29NXfno
  14. https://golang.org/pkg/math/
  15. https://golang.org/pkg/math/#Inf
  16. https://golang.org/pkg/math/#NaN
  17. https://golang.org/pkg/math/#IsInf
  18. https://golang.org/pkg/math/#IsNaN
  19. https://www.golang-book.com/books/intro/3
  20. http://golang-examples.tumblr.com/post/86795367134/fmt-printf-format-reference-cheat-sheet
  21. http://play.golang.org/p/7Ofcns7kWR

3. Variables, Constants, and Types

Once the Go Playground loads up, clear whatever is written on the screen and type:

Program: vandt.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 var x int
 6 
 7 func main() {
 8 	p := 5
 9 	var q int
10 	fmt.Println("p is: ", p)
11 	fmt.Println("q is: ", q)
12 	fmt.Println("x is: ", x)
13 }

When we run the program, the output is:

p is:  5
q is:  0
x is:  0

3.1 Variable

A variable is a storage location for holding a value. The set of permissible values is determined by the variable’s type.

The var statement declares a list of variables.

A var statement can be at package or function level as seen in the above program.

Go can infer the type of the declared type. For integer literals Go infers type int, for floating-point literals Go infers type float64, and for complex literals Go infers type complex128 (the numbers in their names refer to how many bits they occupy). The normal practice is to leave types unspecified unless we want to use a specific type that Go won’t infer.

In the above program we have p := 5 which means that if an initializer is present, the type can be omitted; the variable will take the type of the initializer. Inside a function, the := short assignment statement can be used in place of a var declaration with implicit type. Outside a function the := construct is not available.

Here Go automatically allocates some memory for the variable p - the size of the memory allocated here is that required by a single integer. Since we have also said p := 5, the integer value 5 is assigned to that memory space after the space is allocated. For variable q, no assignment has been stated. However, Go assigns a “zero-value” by default to most data types. For numeric fields, the value is 0.

Also note that p := 5 is the same as var p int = 5. Observe that in Go we declare the type1 after the variable name as in var q int. int is either 32 or 64 bits.

Multiple var declarations may also be grouped; const and import also allow this. Note the use of parentheses:

1 var (
2         x int
3         b bool
4 )

Multiple variables of the same type can also be declared on a single line:

var x, y int

makes x and y both int variables.

You can also make use of parallel assignment:

a, b := 35, 9

Which makes a and b both integer variables and assigns 35 to a and 9 to b.

Declared, but otherwise, unused variables are a compiler error in Go. The following code:

1 package main
2 
3 func main() {
4         var p int
5 }

generates this error:

p declared and not used

Note: A list of common mistakes you can avoid is available3.

Go is statically typed. Every variable has a static type, that is, exactly one type known and fixed at compile time: int, float32, *MyType, []byte, and so on. If we declare:

1 type MyInt int
2 
3 var i int
4 var j MyInt

then i has type int and j has type MyInt. The variables i and j have distinct static types and, although they have the same underlying type, they cannot be assigned to one another without a conversion.

Reference: The above has been mentioned in the Go Blog: The Laws of Reflection4

3.2 Constants

Constants are declared like variables, but with the const keyword. Constants can be character, string, boolean, or numeric values. Constants cannot be declared using the := syntax. Numeric constants are high-precision values.

The convention in Go for constants is to use MixedCaps or mixedCaps rather than underscores or all CAPS, to write multiword constant names.

1 const secretKey = 23232390 // Good
2 const SecretKey = 23232390 // Good
3 const secret_key = 23232390 // Bad
4 const SECRETKEY =23232390 // Bad

3.2.1 Typed and Untyped constants

1 // Untyped Constants.
2 const ui = 12345    // kind: integer
3 const uf = 3.141592 // kind: floating-point
4 const hi = "Hello"  // kind: string
5 
6 // Typed Constants
7 const ti int = 12345        // kind: integer with int64 precision restrictions.
8 const tf float64 = 3.141592 // kind: floating-point with float64 precision restrictions.

In the code snippet above, hi is an untyped string constant. An untyped constant is just a value, one not yet given a defined type that would force it to obey the strict rules that prevent combining differently typed values.

Rob Pike’s article5 has a detailed coverage of untyped and typed constants.

3.3 Named types

Named types are another way to create user defined types. They provide some interesting feature/functionality that is not always available in other languages. The standard library in Go used named types very effectively.

Two examples:

Clear the Go Playground screen of whatever is written there and type:

Program: sample1.go
 1 // Sample program to show how to declare and use a named type.
 2 package main
 3 
 4 import "fmt"
 5 
 6 // Duration is a named type that represents a duration
 7 // of time in Nanosecond.
 8 type Duration int64
 9 
10 func main() {
11 	// Declare a variable of type Duration
12 	var duration Duration
13 	fmt.Println(duration)
14 
15 	// Declare a variable of type int64 and assign a value.
16 	nanosecond := int64(10)
17 
18 	// Attemped to assign a variable of type
19 	// int64 (base type of Duration) to
20 	// a variable of type Duration.
21 	duration = nanosecond
22 
23 	// error: cannot use nanosecond (type int64) as type
24 	// Duration in assignment
25 }

When we run the program, the output is:

main.go:21: cannot use nanosecond (type int64) as type Duration in assignment

Clear the Go Playground screen of whatever is written there and type:

Program: sample2.go
 1 // Sample program to show how to declare and use a named type.
 2 package main
 3 
 4 import "fmt"
 5 
 6 // Duration is a named type that represents a duration
 7 // of time in Nanosecond.
 8 type Duration int64
 9 
10 func main() {
11 	// Declare a variable of type Duration
12 	var duration Duration
13 	fmt.Println(duration)
14 
15 	// Declare a variable of type int64 and assign a value.
16 	nanosecond := int64(10)
17 
18 	// Attemped to assign a variable of type
19 	// int64 (base type of Duration) to
20 	// a variable of type Duration.
21 	// duration = nanosecond
22 
23 	// error: cannot use nanosecond (type int64) as type
24 	// Duration in assignment
25 
26 	// Convert a value of type int64 to type Duration.
27 	duration = Duration(nanosecond)
28 	fmt.Println(duration)
29 }

When we run the program, the output is:

0
10

3.4 Boolean types

A boolean type represents the set of boolean truth values denoted by the predeclared constants true and false. The boolean type is bool.

3.5 Operators

Go supports the normal set of numerical operators. The table below lists the current ones and their relative precedence. They all associate from left to right.

Precedence Operator(s)
Highest * / % << >> & &^
  + - | ^
  == != < <= > >=
  <-
  &&
Lowest ||

Although Go does not support operator overloading (or method overloading for that matter), some of the built-in operators are overloaded. For instance, + can be used for integers, floats, complex numbers and strings (adding strings is concatenating them).

3.5.1 Boolean Operators

Syntax Description/Result
!b Logical not operator; false if Boolean expression b is true
a || b Short-circuit logical OR operator; true if either Boolean
  expression a or b is true
a && b Short-circuit logical AND operator; true if both Boolean
  expressions a and b are true
x < y true if expression x is less than expression y
x <= y true if expression x is less than or equal to expression y
x == y true if expression x is equal to expression y
x != y true if expression x is not equal toexpression y
x >= y true if expression x is greater than or equal to expression y
x > y true if expression x is greater than expression y

3.5.2 Arithmetic Operators

Syntax Description/Result
+x x
-x The negation of x
x++ Increments x by the untyped constant 1
x-- Decrements x by the untyped constant 1
x += y Increments x by y
x -= y Decrements x by y
x *= y Sets x to x multiplied by y
x /= y Sets x to x divieded by y; if the numbers are integers any
  remainder is discarded; division by zero causes a runtime panic
x + y The sum of x and y
x - y The result of subtracting y and x
x * y The result of multiplying y and x
x / y The result of dividing y and x; if the numbers are integers any
  remainder is discarded; division by zero causes a runtime panic

Although Go has sensible rules of precedence, it is recommended to use parentheses to make intentions clear. Using parentheses is particularly recommended for programmers who use multiple languages so as to avoid subtle mistakes.

3.5.3 Bitwise Operators

There are many good online tutorials on Bitwise operators and we shall not be talking about the same. Here’s one6.

Just remember that many languages use ~ as the unary NOT operator (i.e. bitwise complement), but Go reuses the XOR operator (^) for that. Go also has a special ‘AND NOT’ bitwise operator (&^).

3.6 Solutions

Exercise 2 Solution7.

Exercise 3 Solution8.

Exercise 4 Solution9.

Exercise 5 Solution10.

  1. http://golang.org/ref/spec#Types
  2. https://github.com/golang/go/wiki/CodeReviewComments#variable-names
  3. https://github.com/golang/go/wiki/CodeReviewComments
  4. http://blog.golang.org/laws-of-reflection
  5. https://blog.golang.org/constants
  6. http://code.tutsplus.com/articles/understanding-bitwise-operators–active-11301
  7. http://play.golang.org/p/LtFP2Gkpdi
  8. http://play.golang.org/p/-3EAKb4ZGe
  9. http://play.golang.org/p/NZ1N721NbY
  10. http://play.golang.org/p/pol2hdWsTy

4. Control Structures

4.1 if-else

Program: cs1.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6 	x, y := 30, 45
 7 	if x < y {
 8 		fmt.Println("x is less than y")
 9 	} else if x > y {
10 		fmt.Println("x is greater than y")
11 	} else {
12 		fmt.Println("x is equal to y")
13 	}
14 }

Run the above program and the output that you will see is:

x is less than y

Note:

  • There may be zero or more else if clauses and zero or one final else clause. Each block consists of zero or more statements.
  • The expression after the if and the else if has to evaluate to one of the bool types: true or false.
  • There are no parentheses required around the boolean expression - you can have a parentheses, but you don’t have to have it.
  • Go requires the curly braces and the if else keywords to be on the same line with the corresponding braces. If not you will see errors.
  • You can have the explicit values like true or false, or you can also use any expression that evaluates to a true or false.
  • Note that types like an int cannot be used as truth values - this is unlike languages like C, where you can use integers and pointers as truth values.

4.2 goto statement

Go has a goto statement, which you should use wisely. With goto you jump to a label which must be defined within the current function. For instance:

Program: cs2.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6         i := 0
 7 Label:                // First word on a line ending with a colon is a label
 8         fmt.Println(i)
 9         i++
10         if i > 50 {
11                 goto Escape
12         }
13 
14         goto Label   // Jump
15 Escape:              // Label
16         fmt.Println("Get out of here...")
17 }

The name of the label is case sensitive.

4.3 switch

The general format of the switch is:

1 switch any expression of type T {
2 case any expression of same type T: { code to be executed if the case expression is equal \
3 to the switch expression }
4 case any expression of same type T: { code to be executed if this case expression is equal\
5  to the switch expression }
6 //any number of case statements are allowed
7 default: { code to be executed if none of the case expressions match the switch expression\
8  }
9 }

Points to note:

  • the type of the evaluated value in the switch and the case should match. For example, if the switch expression evaluates to an int and the case expression evaluates to a string, then there will be a compile error
  • if there is no expression at all in the switch, then by default it is bool. The block that evaluates to true is executed, and none of the others are executed
  • if more than one case statements match, then the first in the lexical order is executed
  • unlike certain other languages, each case block is independent and the code does not “fall through” (each of the case code blocks are like independent if-else code blocks.)
  • the default code block is executed if none of the other case blocks match
  • the case expressions need not be just constants and can have expressions
  • the use of curly braces for demarcating the code blocks is optional
  • the default statement is optional
  • any number of case statements are allowed - even zero case statements are valid, though that wouldn’t be very useful
  • multiple expressions can be used, each separated by commas in the case statement
  • the default block can be anywhere within the switch block, and not necessarily last in the lexical order

Please refer to Control structures - Go switch case statement1 for more information.

Program: cs3.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6 	switch {
 7 	default:
 8 		fmt.Println("I am default")
 9 	case false:
10 		fmt.Println("I am false")
11 	case true:
12 		fmt.Println("I am true")
13 	}
14 }
Program: cs4.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6 	i := 5
 7 	switch i {
 8 	case 4:
 9 		fmt.Println("number 4")
10 	case i > 8:
11 		fmt.Println("i is > 8")
12 	default:
13 		fmt.Println("default")
14 	}
15 }

4.3.1 fallthrough statement

In certain languages like C and Java, the switch-case statement behaves slightly differently from Go: when a case block is executed, all the case blocks below it are also executed, unless explicitly terminated (by say using a break statement). In Go, this is not the default behavior, but if you want to achieve the same result, then use the fallthrough statement to indicate that the case block following the current one has to be executed.

1 k := 3
2 switch k {
3 case 3: fmt.Println("was <= 3"); fallthrough;
4 case 4: fmt.Println("was <= 4"); fallthrough;
5 ...

4.4 for loop

Go has only one looping construct, the for loop.

The basic for loop looks as it does in C or Java, except that the ( ) are gone (they are not even optional) and the { } are required.

There are three forms of for, only one of which has semicolons.

1 // Like a C for
2 for init; condition; post { }
3 
4 // Like a C while
5 for condition { }
6 
7 // Like a C for(;;)
8 for {
9 }

Here’s an example:

Program: cs5.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6         sum := 0
 7         for i := 0; i < 100; i++ {
 8                 sum += i
 9         }
10         fmt.Println(sum)
11 }

The output of the program is 4950.

The above program is available here2.

Here are some code snippets and their explanation:

1 func main() {
2         sum := 1
3         // As in C or Java, you can leave the
4         // pre and post statements empty.
5         for ; sum < 100; {
6                 sum += sum
7         }
8         fmt.Println(sum)
9 }
1 func main() {
2         sum := 1
3         // You can drop the semicolons
4         // for behaves like C's while
5         for sum < 1000 {
6                 sum += sum
7         }
8         fmt.Println(sum)
9 }
1 func main() {
2         // infinite loop
3         for {
4         }
5 }

The break keyword allows you to terminate a loop at a point and continue execution at the statement following the end of the for loop block.

An example:

Program: cs6.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6 	i := 0
 7 	for {
 8 		if i >= 10 {
 9 			break
10 		}
11 		fmt.Println("Value of i is:", i)
12 		i++
13 	}
14 	fmt.Println("A statement just after the for loop.")
15 }

With the continue keyword you begin the next iteration of the loop, skipping any remaining code. In the same way as break, continue also accepts a label.

The following loop prints 0 to 5.

Program: cs7.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6 	for i := 0; i < 10; i++ {
 7 		if i > 5 {
 8 			// Skip the rest of the remaining code in the loop
 9 			continue
10 		}
11 		fmt.Println(i)
12 	}
13 }

A nested for loop example:

Program: cs8.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6 L:
 7 	for {
 8 		for {
 9 			break L
10 		}
11 	}
12 	fmt.Println("Break out of nested loops")
13 }
O
OO
OOO
OOOO
OOOOO
OOOOOO
OOOOOOO
OOOOOOOO
OOOOOOOOO
OOOOOOOOOO

4.5 Solutions

Exercise 6 Reason: If there is no expression at all in the switch, then by default it is bool. The block that evaluates to true is executed, and none of the others are executed.

Exercise 7 Reason: The program will not compile as the type int and bool don’t match between the case and the switch.

Exercise 8 Solution3.

Exercise 9 Solutions. Part a4 and Part b5.

Exercise 10 Solution6.

  1. http://golangtutorials.blogspot.in/2011/06/control-structures-go-switch-case.html
  2. http://play.golang.org/p/Pixi9AFeX6
  3. http://play.golang.org/p/qN6fy8LSUb
  4. http://golang.org/doc/faq#no_pointer_arithmetic
  5. https://play.golang.org/p/IclWz08hNa
  6. https://play.golang.org/p/Tg6oG0pVDt

5. Pointers

According to Wikipedia1: A pointer references a location in memory, and obtaining the value stored at that location is known as de-referencing the pointer. As an analogy, a page number in a book’s index could be considered a pointer to the corresponding page; de-referencing such a pointer would be done by flipping to the page with the given page number.

When there is a value stored in memory, it is stored in a physical location. This location is called its address. Many programming languages, including Go, allows you to access the data in a location by specifying its location in memory.

Unlike C, Go has no pointer arithmetic. Do read “Why is there no pointer arithmetic?”2

You obtain the address of a variable by using the & symbol before the variable name. Let’s look at a simple example:

Program: ptr1.go
1 package main
2 
3 import "fmt"
4 
5 func main() {
6         i := 10
7         fmt.Println("The value of i is  : ", i)
8         fmt.Println("The address of i is: ", &i)
9 }

The output is:

The value of i is  :  10
The address of i is:  0x1043617c

The actual value of the address will differ from machine to machine and even on different executions of the same program as each machine could have a different memory layout and also the location where it is allocated could be different.

Normal programs do not use the numeric value of the address for anything. Instead, what they usually use is the value referenced by the address. You can get the value at an address by using the * symbol before the address.

Let’s look at another example:

Program: ptr2.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6         v := 50
 7 
 8         fmt.Println("The value of v is                       : ", v)
 9         fmt.Println("The address of v is                     : ", &v)
10         fmt.Println("The value at address ", &v, " is    : ", *(&v))
11 }

The output is:

The value of v is                       :  50
The address of v is                     :  0x113a21e0
The value at address  0x113a21e0  is    :  50

When a variable holds an address, it is called a pointer. Therefore in the example:

ptr := &v

ptr is a pointer and it holds the address the of v. Putting it differently, ptr is a pointer to the variable v. You could also say that ptr is a reference to the variable v.

Let’s look at an example:

Program: ptr3.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6 	i, j := 20, 5000
 7 
 8 	p := &i         // point to i
 9 	fmt.Println(*p) // read i through the pointer
10 	*p = 25         // set i through the pointer
11 	fmt.Println(i)  // see the new value of i
12 
13 	p = &j         // point to j
14 	*p = *p / 10   // divide j through the pointer
15 	fmt.Println(j) // see the new value of j
16 }

The output is:

20
25
500

Few more examples:

Program: ptr4.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6         a := 5
 7         var ptr *int
 8 
 9         ptr = &a
10 
11         fmt.Println(ptr)
12 }

The output on my machine is:

0x1043617c

Recollect that the built-in function new allocates memory. new can be applied to types like int, string etc.

Program: ptr5.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6         // What new will return back to you is a pointer
 7         // to a location in memory set aside that can 
 8         // hold the type you specified.
 9         x := new(string) // Here string is a type
10         
11         // A benefit of using new is you can simply 
12         // use the variable (pointer) without having to
13         // use the & operator
14         *x  = "Hello"
15         fmt.Println(*x)
16 }

The output is:

Hello
Program: ptr6.go
1 package main
2 
3 import "fmt"
4 
5 func main() {
6         v := new(int)
7         *v++
8         fmt.Println(*v)
9 }

The output is:

1
1 package main
2 
3 func main() {
4         const i = 5
5         ptr1 := &i
6         ptr2 := &10
7 }
1 package main
2 
3 func main() {
4         var p *int  // Declare a nil value pointer
5         *p = 10     
6 }

5.1 Solutions

Exercise 11 Reason: You can only take the pointer to a variable and not to a literal value or a constant.

Exercise 12 Reason: If our code attempts to read or write to address 0x0, the hardware will throw an exception that will be caught by the Go runtime and reported back up to our program in the form of a panic. If the panic is not recovered, a stack trace is produced.

  1. https://en.wikipedia.org/wiki/Pointer_(computer_programming)
  2. http://golang.org/doc/faq#no_pointer_arithmetic

6. More on Functions

Functions are reusable units of code. Considering the black-box analogy, a function is a black unit of code to the outside, which is stimulated by some well known inputs (arguments or parameters) to do some work and then produce an outcome (either an output or a result). Functions are declared / defined once and used many times.

func (p mytype) funcname(q int) (r,s int) { return 0,0 }

  • The keyword func is used to declare a function.
  • A function can optionally be bound to a specific type. This is called the receiver.
  • funcname is the name of your function.
  • The variable q of type int is the input parameter. The parameters are passed pass-by-value meaning they are copied.
  • Go requires explicit returns, i.e. it won’t automatically return the value of the last expression.
  • The variables r and s are the named return parameters for this function. Functions in Go can have multiple return values. If you want the return parameters not to be named you only give the types: (int, int). If you have only one value to return you may omit the parentheses.
  • { return 0,0 } is the function’s body. Note that return is a statement so the braces around the parameter(s) are optional.
  • Functions can be declared, in a program, in any order you wish. The compiler scans the entire file before execution, so function prototyping is a thing of the past in Go.
  • Function names starting with a capital letter are exported outside the package, that is, they are visible and can be used by other packages; then they follow PascalCasing eg. MyFunctionInGo().
  • When a function is not exported outside a package; then they follow camelCasing: every new word in the name starts with a capital letter eg. myFunctionInGo().
  • Functions are values. Functions can be passed around just like any other value. A function’s type signature describes the types of its arguments and return values.

Examples:

Here are two examples. The first is a function without a return value, while the next one is a simple function that returns its input.

func subroutine(in int ) { return }
func identity(in int ) int { return in }

6.1 A function can have multiple return values. Some examples:

1 x, err := f()

Here is another example:

1 func f() (int, int) {
2         return 5, 6
3 }
4 
5 func main() {
6         x, y := f()
7 }

Note: Three changes are necessary: change the return type to contain multiple types separated by comma, change the expression after the return so that it contains multiple expressions separated by comma and finally change the assignment statement so that multiple values are on the left side of the := or =.

It is legitimate to discard some or all of a function’s return values by assigning them to the blank identifier (_). However, if no return values are wanted it is more conventional to simply ignore them.

Here’s an example:

Program: func1.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func multipleVals()(string, int){
 6         return "Go-Lang",100
 7 }
 8 
 9 func main() {
10         lang, number := multipleVals()
11         fmt.Println(lang)
12         fmt.Println(number)
13     
14         // Ignore the first return value with Blank identifier
15         _, anotherNum := multipleVals() 
16         fmt.Println(anotherNum)
17 }

The output is:

Go-Lang
100
100

6.2 A function can take zero or more arguments

1 func add(x int, y int) int {
2         return x + y
3 }

When two or more consecutive named function parameters share a type, you can omit the type from all but the last.

Program: func2.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func add(i, j int) int {
 6 	return i + j
 7 }
 8 
 9 func main() {
10 	fmt.Println(add(42, 13))
11 }

In the above example, we shortened i int, j int to i, j int.

This section is referred from A Tour of Go.1

6.3 Named return values

Go’s return values may be named and act just like variables. These names should be used to document the meaning of the return values.

A return statement without arguments returns the current values of the results. This is known as a “naked” return. Naked return statements should be used only in short functions, as with the example shown here. They can harm readability in longer functions.

Program: func3.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func split(sum int) (x, y int) {
 6         x = sum * 4 / 9
 7         y = sum - x
 8         return
 9 }
10 
11 func main() {
12         fmt.Println(split(17))
13 }

This section is referred from A Tour of Go.2

6.4 What’s the idiomatic way to exit a program with some error code?

func Exit(code int)

Exit causes the current program to exit with the given status code. Conventionally, code zero indicates success, non-zero an error. The program terminates immediately; deferred functions are not run.

You can do something along these lines in most of your real main packages, so that the return err convention is adopted as soon as possible, and has a proper termination:

Program: pexit.go
 1 // part code
 2 func main() {
 3         if err := run(); err != nil {
 4             fmt.Fprintf(os.Stderr, "error: %v\n", err)
 5             os.Exit(1)
 6         }
 7 }
 8 
 9 func run() error {
10         err := something()
11         if err != nil {
12                 return err
13         }
14         // etc
15 }
Program: ex11.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 var i = 10
 6 
 7 func main() {
 8 	a()
 9 	b()
10 	a()
11 }
12 
13 func a() {
14 	fmt.Println(i)
15 }
16 
17 func b() {
18 	i := 20
19 	fmt.Println(i)
20 }

The output when you run the above program is:

10
20
10
Program: ex12.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 var i int
 6 
 7 func main() {
 8 	i := 20
 9 	fmt.Println(i)
10 	b()
11 }
12 
13 func b() {
14 	i := 40
15 	fmt.Println(i)
16 	a()
17 }
18 
19 func a() {
20         fmt.Println(i)
21 }

The output when you run the above program is:

20
40
0

6.5 Variadic Functions

We have discussed this along with range in “Variadic Functions using range” in a later chapter.

6.6 Closures

The material on Closures and Recursion has been adapted from An Introduction to Programming in Go.3

It is possible to create functions inside of functions:

Program: func4.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6         x := 0
 7         increment := func() int {
 8                 x++
 9                 return x
10         }
11         fmt.Println(increment())
12         fmt.Println(increment())
13 }

The output is:

1
2

increment is a local variable that has the type func() int (a function that takes no parameters and returns an int).

increment adds 1 to the variable x which is defined in the main function’s scope. This x variable can be accessed and modified by the increment function. This is why the first time we call increment we see 1 displayed, but the second time we call it we see 2 displayed.

A function like this together with the non-local variables it references is known as a closure. In this case increment and the variable x form the closure.

One way to use closure is by writing a function which returns another function which – when called – can generate a sequence of numbers. For example here’s how we might generate odd numbers:

Program: func5.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 //This function makeOddGenerator returns
 6 //another function, which we define anonymously
 7 //in the body of makeOddGenerator
 8 func makeOddGenerator() func() int {
 9         i := 1
10         return func() int {
11                 i += 2
12                 return i
13         }
14 }
15 
16 func main() {
17         nextOdd := makeOddGenerator()
18         fmt.Println(nextOdd())
19         fmt.Println(nextOdd())
20         fmt.Println(nextOdd())
21 
22         //To confirm that the state is unique
23         //to that particular function, create
24         //and test a new one
25         newOdd := makeOddGenerator()
26         fmt.Println(newOdd())
27         fmt.Println(newOdd())
28         fmt.Println(newOdd())
29 }

The output is:

3
5
7
3
5
7

Closures are syntactically lighter than a named function. So, if there’s a scenario where a function is used only once or a limited number of times it’s better to go for Closures.

6.7 Recursion

Go supports recursive functions i.e. a function is able to call itself. Here’s a classic factorial example:

Program: func6.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func fact(n int) int {
 6         if n == 0 {
 7                 return 1
 8         }
 9         return n * fact(n-1)
10 }
11 func main() {
12         fmt.Println(fact(8))
13 }

Closure and recursion are powerful programming techniques which form the basis of a paradigm known as functional programming. Most people will find functional programming more difficult to understand than an approach based on for loops, if statements, variables and simple functions.

6.8 Solutions

Exercise 13 Reason: Variables declared outside any functions are global in Go, those defined in functions are local to those functions. If names overlap — a local variable is declared with the same name as a global one — the local variable hides the global one when the current function is executed.

Exercise 14 Reason: A local variable is only valid when we are executing the function in which it is defined.

Fun YES…BUT THERE’S MORE…

  1. https://tour.golang.org/basics/5
  2. https://tour.golang.org/basics/7
  3. https://www.golang-book.com/books/intro/7

7. Detailed information

7.1 Semicolons

Like C, Go’s formal grammar uses semicolons to terminate statements1, but unlike in C, those semicolons do not appear in the source.

Idiomatic Go programs have semicolons only in places such as for loop clauses, to separate the initializer, condition, and continuation elements. They are also necessary to separate multiple statements on a line, should you write code that way.

One consequence of the semicolon insertion rules is that you cannot put the opening brace of a control structure (if, for, switch, or select) on the next line. If you do, a semicolon will be inserted before the brace, which could cause unwanted effects. Write them like this:

if i < f() {
        g()
}

not like this:

7.2 init

Every Go package may contain one or more init() functions specifying actions that should be taken during program initialisation. Here, multiple declarations of the same identifier can occur without either resulting in a compilation error or the shadowing of a variable.

Program: my_init.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 const Hello = "Hi!"
 6 var world string
 7 
 8 func init() {
 9         world = "My world."
10 }
11 
12 func main() {
13         fmt.Println(Hello, world)
14 }

The output is:

Hi! My world.

7.3 Formatting

A Go program can be formatted in (almost) any way the programmers want. With Go, let the machine take care of most formatting issues. The gofmt program2 (also available as go fmt, which operates at the package level rather than source file level) reads a Go program and emits the source in a standard style of indentation and vertical alignment, retaining and if necessary reformatting comments.

So if your program name is hello.go then format it as follows:

go fmt hello.go

The output of the filter gofmt is the officially endorsed format.

The cool thing about Go code is that the officially endorsed format includes tabs, and so if you like having your tabs present as the traditional 8 spaces, go ahead. If you want them to present as 2 spaces, go ahead, if you want them to present as 4 spaces, or 20 spaces, you are not affecting anyone else with your preferences.

7.4 More on Strings

Strings3 are a sequence of UTF-8 characters (one-byte UTF-8 codes have the same value as the corresponding ASCII code). UTF-8 is the most widely used encoding, the standard encoding for text files, XML files and JSON strings. While able to represent characters that need 4 bytes, ASCII-characters are still stored using only 1 byte. A Go string is thus a sequence of variable-width characters (each 1 to 4 bytes), contrary to strings in other languages as C++, Java or Python that are fixed-width (Java uses always 2 bytes).

The advantages are that Go strings and text files occupy less memory/disk space, and since UTF-8 is the standard, Go does not need to encode and decode strings as other languages have to do. Strings are value types and immutable: once created you cannot modify the contents of the string.

A Go string is a sequence of variable-width characters where each character is represented by one or more bytes, normally using the UTF-8 encoding. Strings are length-delimited and not terminated by a special character as in C/C++.

The initial (default) value of a string is the empty string "".

String literals have type string. String literals are of two types:

  • Interpreted strings i.e. surrounded by "" (double quotes).
  • Raw strings i.e. surrounded by back quotes.

They are not interpreted; they can span multiple lines. In the literal `This is a raw string \n` the \n is not interpreted but taken literally.

7.4.1 String functions

The standard library’s strings4 package provides many useful string-related functions. Here are a few in action:

Program: my_string.go
 1 package main
 2 
 3 import "fmt"
 4 import s "strings"
 5 
 6 // We alias fmt.Println to a shorter name
 7 var p = fmt.Println
 8 
 9 func main() {
10         // Note that these are all functions from package, not methods on the
11         // string object itself. This means that we need pass the string in
12         // question as the first argument to the function.
13         p("ToLower:   ", s.ToLower("TEST"))
14         p("ToUpper:   ", s.ToUpper("test"))
15         p("Split:     ", s.Split("a-b-c-d-e", "-"))
16         p("Index:     ", s.Index("test", "e"))
17         p("Contains:  ", s.Contains("test", "es"))
18         p("Count:     ", s.Count("test", "t"))
19 }

The output is:

ToLower:    test
ToUpper:    TEST
Split:      [a b c d e]
Index:      1
Contains:   true
Count:      2

7.5 defer

Go has a special statement called defer6 which schedules a function call to be run after the function completes.

defer is often used when resources need to be freed in some way. For example when we open a file we need to make sure to close it later. With defer:

1 file, err := os.Open("hello.go")
2 check(err)
3 defer file.Close()

This has 3 advantages:

  • it keeps our Close call near our Open call so its easier to understand,
  • if our function had multiple return statements (perhaps one in an if and one in an else) Close will happen before both of them and
  • deferred functions are run even if a run-time error occurs.

Another example showing that defer runs when the function returns and not when the scope is exited Also, that defer’ed function calls are run in LIFO order:

Program: my_defer.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func f() {
 6         for i := 0; i < 5; i++ {
 7                 defer func(n int) { fmt.Println("bye", n) }(i)
 8                 fmt.Println(i)
 9         }
10 }
11 
12 func main() {
13         f()
14 }

The output is:

0
1
2
3
4
bye 4
bye 3
bye 2
bye 1
bye 0

7.6 Using the log package

Usage: import "log"

Package log implements a simple logging package. It defines a type, Logger, with methods for formatting output. It also has a predefined ‘standard’ Logger accessible through helper functions Print[f|ln], Fatal[f|ln], and Panic[f|ln], which are easier to use than creating a Logger manually. That logger writes to standard error and prints the date and time of each logged message. The Fatal functions call os.Exit(1) after writing the log message. The Panic functions call panic after writing the log message.

Example: log.Fatal(err)

7.7 Using the big package

Package big implements multi-precision arithmetic (big numbers). The following numeric types are supported:

  • Int signed integers
  • Rat rational numbers

func NewInt(x int64) *Int

NewInt allocates and returns a new Int set to x.

func (z *Int) Mul(x, y *Int) *Int

Mul sets z to the product x*y and returns z.

Here’s an example:

Program: bigex.go
 1 package main
 2 
 3 import (
 4         "fmt"
 5         "math/big"
 6 )
 7 
 8 func main() {
 9         verybig := big.NewInt(1)
10         ten := big.NewInt(10)
11 
12         for i:=0; i<10000; i++ {
13                 temp := new(big.Int)
14                 temp.Mul(verybig, ten)
15                 verybig = temp
16         }
17 
18         fmt.Println(verybig)
19 }

The output is:

1000.....

Note: If you want it to run fast enough for Go Playground, use a smaller exponent than 100000.

7.8 go vet

go vet7 is used for analysing Go code and finding common mistakes. Among many it checks for some common mistakes like:

  • Useless assignments
  • Comparing functions with nil
  • Using wrong printf format specifiers
  • Closing over loop variables the wrong way
  • Unreachable code
  • Mistakes involving boolean operators

7.9 golint

Go is a tool8 for managing Go source code.

Usage: go command [arguments] where get is one of the many commands available.

go get downloads and installs the packages named by the import paths, along with their dependencies.

Install golint with go get github.com/golang/lint/golint

While go vet checks your code for actual programming errors, golint checks your code for style violations.

Golint does not emit errors or warnings, but “suggestions”: These suggestions can be wrong at times, and code that golint complains about isn’t necessarily wrong – it might just be hitting a false positive. Nevertheless, it’s more often right than wrong, and you should definitely run golint on your code from time to time and fix those suggestions that it is right about.

7.10 goimports

Install goimports with go get golang.org/x/tools/cmd/goimports

Do you wish Go would just allow you to import unused packages? Or are you even tired of having to manually import all those packages you use? Then goimports might be for you. It’s a replacement for gofmt that, in addition to formatting your code, it also manages your imports for you.

It removes unused imports and adds missing imports.

Usage: goimports -w go_program.go

7.11 Naming Convention Summary

There is no detailed coding style guide for Golang.

Here are some references that would help:

  1. Go Code Review Comments9
  2. How to write Go code10
  3. Godoc: Documenting Go code11
  4. Effective Go12

Between gofmt, golint and go vet, you cover already a lot of conventions.

Do read “Is there a Go programming style guide?”13

  1. https://golang.org/doc/effective_go.html#semicolons
  2. https://golang.org/doc/effective_go.html#formatting
  3. https://blog.golang.org/strings
  4. http://golang.org/pkg/strings/
  5. https://www.socketloop.com/tutorials/golang-reverse-a-string-with-unicode
  6. https://golang.org/doc/effective_go.html#defer
  7. https://golang.org/cmd/go/#hdr-Run_go_tool_vet_on_packages
  8. https://golang.org/cmd/go/
  9. https://github.com/golang/go/wiki/CodeReviewComments
  10. https://golang.org/doc/code.html
  11. http://blog.golang.org/godoc-documenting-go-code
  12. https://golang.org/doc/effective_go.html
  13. http://golang.org/doc/faq#Is_there_a_Go_programming_style_guide

8. Arrays

In Go, an array is a numbered sequence of elements of a specific length.

Arrays are easily understood with the help of this example:

Program: ar1.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6         //exactly 5 ints. The type of elements
 7         //and length are both part of the array's
 8         //type. By default an array is zero-valued,
 9         //and int types are by default initialized 
10         //with a 0 value.
11         var arr [5]int
12         fmt.Println("arr:", arr)
13 
14         //We can set a value at an index using the
15         //array[index] = value syntax, and get a
16         //value with array[index].
17         arr[3] = 10
18         fmt.Println("set:", arr)
19         fmt.Println("get:", arr[3])
20 
21         //The builtin len returns the length of
22         //an array
23         fmt.Println("len:", len(arr))
24 
25         //Use this syntax to declare and initialize
26         //an array in one line.
27         arr2 := [5]int{1, 2, 3, 4, 5}
28         fmt.Println("arr2:", arr2)
29 
30         //multidimensional array
31         arr3 := [2][2] int{ {1,2}, {3,4} }
32         fmt.Println("arr3:", arr3)
33 }

The output is:

arr: [0 0 0 0 0]
set: [0 0 0 10 0]
get: 10
len: 5
arr2: [1 2 3 4 5]
arr3: [[1 2] [3 4]]

Note that you can have the compiler count the array elements for you:

b := [...]string{"Golang", "Challenge"}

In both cases, the type of b is [2]string.

Go’s arrays are values. An array variable denotes the entire array; it is not a pointer to the first array element (as would be the case in C). This means that when you assign or pass around an array value you will make a copy of its contents. (To avoid the copy you could pass a pointer to the array, but then that’s a pointer to an array.)

The in-memory representation of [4]int is just four integer values laid out sequentially:

Array
Array

9. Slices

Arrays are a bit inflexible, so you don’t see them too often in Go code. Slices, though, are everywhere. They build on arrays to provide great power and convenience.

A slice is a segment of an array. Like arrays, slices are indexable and have a length. Unlike arrays, this length is allowed to change. Here’s an example of a slice:

var x []int

The only difference between this and an array is the missing length between the brackets. In this case x has been created with a length of 0.

If you want to create a slice you should use the built-in make function:

x := make([]int, 5)

This creates a slice that is associated with an underlying int array of length 5. Slices are always associated with some array, and although they can never be longer than the array, they can be smaller or equal.

The make function also allows a 3rd parameter:

x := make([]int, 5, 10)

10 represents the capacity of the underlying array which the slice points to. When the capacity argument is omitted, it defaults to the specified length.

The length and capacity of a slice can be inspected using the built-in len and cap functions.

len(x) == 5
cap(x) == 10

Another way to create slices is to use the [low : high] expression:

1 arr := [5]int{1,2,3,4,5}
2 x := arr[0:5]

low is the index of where to start the slice and high is the index where to end it (but not including the index itself). For example while arr[0:5] returns [1,2,3,4,5], arr[1:4] returns [2,3,4].

For convenience we are also allowed to omit low, high or even both low and high. arr[0:] is the same as arr[0:len(arr)], arr[:5] is the same as arr[0:5] and arr[:] is the same as arr[0:len(arr)].

9.1 Slice Functions

Go includes two built-in functions to assist with slices: append and copy. Here is an example of append:

Program: sl1.go
 1 package main
 2 
 3 import (
 4         "fmt"
 5 )
 6 
 7 func main() {
 8         slice1 := []int{10, 20, 30}
 9         slice2 := append(slice1, 40, 50)
10         fmt.Println(slice1, slice2)
11 }

The output is:

[10 20 30] [10 20 30 40 50]

append creates a new slice by taking an existing slice (the first argument) and appending all the following arguments to it.

Here is an example of copy:

Program: sl2.go
 1 package main
 2 
 3 import (
 4         "fmt"
 5 )
 6 
 7 func main() {
 8         slice1 := []int{10, 20, 30}
 9         slice2 := make([]int, 2)
10         copy(slice2, slice1)
11         fmt.Println(slice1, slice2)
12 }

The output is:

[10 20 30] [10 20]

After running this program slice1 has [10,20,30] and slice2 has [10,20]. The contents of slice1 are copied into slice2, but since slice2 has room for only two elements only the first two elements of slice1 are copied.

9.2 Slice internals

A slice is a descriptor of an array segment. It consists of a pointer to the array (ptr in image below), the length of the segment (len), and its capacity (cap - the maximum length of the segment).

Slice
Slice

Now s := make([]int, 5) can be represented as:

Slice
Slice

The length is the number of elements referred to by the slice. The capacity is the number of elements in the underlying array (beginning at the element referred to by the slice pointer).

As we slice s, observe the changes in the slice data structure and their relation to the underlying array:

s = s[2:4]

Slice
Slice

Slicing does not copy the slice’s data. It creates a new slice value that points to the original array. This makes slice operations as efficient as manipulating array indices. Therefore, modifying the elements (not the slice itself) of a re-slice modifies the elements of the original slice.

Program: sl3.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6         arr := [5]int{1, 2, 3, 4, 5}
 7         slice := arr[0:5]
 8         fmt.Println(slice)
 9         fmt.Println("Len is: ", len(slice))
10         fmt.Println("Cap is: ", cap(slice))
11 
12         slice = slice[2:4]
13         fmt.Println(slice)
14         fmt.Println("Len is: ", len(slice))
15         fmt.Println("Cap is: ", cap(slice))
16 }

The output is:

[1 2 3 4 5]
Len is:  5
Cap is:  5
[3 4]
Len is:  2
Cap is:  3

Slicing does not copy the slice’s data. It creates a new slice value that points to the original array. This makes slice operations as efficient as manipulating array indices.

Slices provide a dynamic window onto the underlying array.

9.3 Passing a slice to a function

If you have a function which must operate on an array, create a slice reference and pass that to the function.

For example, here is a function that sums all elements in an array:

Program: sl4.go
 1 package main
 2 
 3 import (
 4         "fmt"
 5 )
 6 
 7 func sum(a []int) int {
 8         s := 0
 9         for i := 0; i < len(a); i++ {
10                 s += a[i]
11         }
12         return s
13 }
14 
15 func main() {
16         var arr = [5]int{0, 1, 2, 3, 4}
17         fmt.Println("Sum is: ", sum(arr[:]))
18 }

The output is:

Sum is:  10

10. Range

range iterates over elements in a variety of data structures.

If you’re looping over an array, slice, string, or map (more about this later), or reading from a channel (more about this later), a range clause can manage the loop.

 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6         nums := []int{2, 3, 4}
 7         sum := 0
 8         for key, value := range nums {
 9                 sum += value
10                 fmt.Println("key: ", key, " sum is: ", sum) 
11         }
12         fmt.Println("Final sum:", sum)
13 }

The output is:

key:  0  sum is:  2
key:  1  sum is:  5
key:  2  sum is:  9
Final sum: 9

If you only need the first item in the range (the key or index), drop the second:

1 for key := range m {
2         if key.expired() {
3                 delete(m, key)
4         }
5 }

If you only need the second item in the range (the value), use the blank identifier, an underscore, to discard the first:

 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6         nums := []int{2, 3, 4}
 7         sum := 0
 8         for _, value := range nums {
 9                 sum += value
10         }
11         fmt.Println("Final sum:", sum)
12 }

The output is:

Final sum: 9

The blank identifier _ as seen above, can be assigned or declared with any value of any type, with the value discarded harmlessly.

Here is a slighly bigger example:

Program: range_ex.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6         nums := []int{2, 3, 4}
 7 
 8         //Here we use range to sum the
 9         //numbers in a slice. Arrays work
10         //like this too.
11         sum := 0
12         for _, num := range nums {
13                 sum += num
14         }
15         fmt.Println("sum:", sum)
16 
17         //range on arrays and slices provides
18         //both the index and value for each entry.
19         //Above we didn't need the index, so we
20         //ignored it with the blank identifier _.
21         //Sometimes we actually want the indexes though.
22         for i, num := range nums {
23                 if num == 3 {
24                         fmt.Println("index:", i)
25                 }
26         }
27 }

The output is:

sum: 9
index: 1

You can also use range on strings directly. Then it will break out the individual Unicode characters and their start position, by parsing the UTF-8.

Program: range_str.go
1 package main
2 
3 import "fmt"
4 
5 func main() {
6         for pos, char := range "a©b" {
7                 fmt.Printf("character '%c' starts at byte position %d\n", char, pos)
8         }
9 }

The output is:

character 'a' starts at byte position 0
character `'©'` starts at byte position 1
character 'b' starts at byte position 3

Observe that ‘b’ starts at position 3, which means '©' took 2 bytes.

We had mentioned earlier that in the UTF-8 world characters are sometimes called runes. Mostly, when people talk about characters, they mean 8 bit characters. As UTF-8 characters may be up to 32 bits the word rune is used. In this case the type of char is rune. The Go language defines the word rune as an alias for the type int32.

A for range loop, by contrast, decodes one UTF-8-encoded rune on each iteration. Each time around the loop, the index of the loop is the starting position of the current rune, measured in bytes, and the code point is its value.

10.1 Variadic Functions using range

There is a special form available for the last parameter in a Go function. They are known as Variadic functions and can be called with any number of trailing arguments. By using ... before the type name of the last parameter you can indicate that it takes zero or more of those parameters.

Here’s a function that will take an arbitrary number of ints as arguments:

 1 package main
 2 
 3 import "fmt"
 4 
 5 func add(args ...int) int {
 6         total := 0
 7         for _, v := range args {
 8                 total += v
 9         }
10         return total
11 }
12 func main() {
13         fmt.Println(add(1, 2))
14         fmt.Println(add(4, 5, 6))
15 }

The output is:

3
15

11. Maps

A Go map is a built-in unordered collection of key-value pairs. Also known as an associative array, a hash table or a dictionary, maps are used to look up a value by its associated key.

To create an empty map, use the built-in make:

1 make(map[key-type]val-type)

Note that the key can be an int, a float, complex number, string, pointer, even an interface that supports equality. We’ll look at interfaces later. We can also have a map like map[string]map[string]string. This is a map of strings to maps of strings to strings.

Let us look at the following Go program:

Program: maps.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6         m := make(map[string]int)
 7 
 8         //Set key/value pairs using typical
 9         //name[key] = val syntax
10         m["k1"] = 7
11         m["k2"] = 13
12 
13         //Printing a map with e.g. Println
14         //will show all of its key/value pairs
15         fmt.Println("map:", m)
16 
17         //Get a value for a key with name[key]
18         v1 := m["k1"]
19         fmt.Println("v1: ", v1)
20 
21         //The builtin len returns the number of
22         //key/value pairs when called on a map
23         fmt.Println("len:", len(m))
24 
25         //The builtin delete removes key/value pairs
26         //from a map
27         delete(m, "k2")
28         fmt.Println("map:", m)
29 
30         //The optional second return value when getting
31         //a value from a map indicates if the key was
32         //present in the map. This can be used to
33         //disambiguate between missing keys and keys
34         //with zero values like 0 or ""
35         _, prs := m["k2"]
36         fmt.Println("prs:", prs)
37 
38         //You can also declare and initialize a new map
39         //in the same line with this syntax
40         n := map[string]int{"foo": 1, "bar": 2}
41         fmt.Println("map:", n)
42 }

The output of the program is:

map: map[k1:7 k2:13]
v1:  7
len: 2
map: map[k1:7]
prs: false
map: map[foo:1 bar:2]

Note: x := make(map[int]int) looks very much like an array but there are a few differences. First the length of a map (found by doing len(x)) can change as we add new items to it. When first created it has a length of 0, after x[1] = 10 it has a length of 1. Second, maps are not sequential. We have x[1], and with an array that would imply there must be an x[0], but maps don’t have this requirement.

12. Structs

Based on what we have learnt so far, how would you write a program that calculates the area and perimeter of a rectangle?

Here’s what you would do:

Program: struct0.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 func Area(length, width float64) float64 {
 6 	return length * width
 7 }
 8 
 9 func Perimeter(length, width float64) float64 {
10 	return 2 * (length + width)
11 }
12 
13 func main() {
14 	length := 4.5
15 	width := 3.75
16 
17 	area := Area(length, width)
18 	fmt.Println("Area is = ", area)
19 
20 	perimeter := Perimeter(length, width)
21 	fmt.Println("Perimeter is = ", perimeter)
22 }

The output is:

Area is =  16.875
Perimeter is =  16.5

However, the way we have written the above program is more on the lines of procedural programming1. Let’s explore how to write the above program using Go’s struts but first understanding what structs in Go are.

Go allows you to define new types, it does this with the type keyword:

type foo int

The above creates a new type foo which acts like an int. Creating more sophisticated types is done with the struct keyword.

A struct is a collection of fields and is defined with the type and struct keywords.

An example:

1 type myStructName struct {
2         x int
3         y string
4 }

The type keyword introduces a new type. It is followed by the name of the type (myStructName), the keyword struct to indicate that we are defining a struct type and a list of fields inside of curly braces. Each field has a name and a type. Like with functions we can collapse fields that have the same type:

1 type Circle struct {
2     x, y, r float64
3 }

Struct fields are accessed using a dot. Here’s an example:

Program: struct1.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 // this struct is visible only in this package
 6 // as it starts with a small letter
 7 type myStructName struct {
 8         // variables starts with small letter,
 9         // so NOT visible outside the package
10         x int
11         y string
12 }
13 
14 func main() {
15         msn := myStructName{1, "talim"}
16         msn.x = 4
17         fmt.Println(msn.x)
18 }

The output is is 4.

Let us define a Square struct as follows:

Program: struct2.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 // this struct is visible outside this package
 6 // as it starts with a capital letter
 7 type Square struct {
 8         // variable X starts with a capital letter,
 9         // so visible outside package
10         X    int
11         name string
12 }
13 
14 func main() {
15         sqr := Square{}
16         fmt.Println("Default square is: ", sqr)
17 }

When you run the example, the output is Default square is: {0 }

This means that in a struct the values of the variables by default for an int will be 0; a string will be empty, etc.

Now let us look at different ways of initializing a struct and setting values for variables within it.

Program: struct3.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 type Square struct {
 6         X    int
 7         name string
 8 }
 9 
10 func main() {
11         //initialize values in order they are defined in struct
12         sqr1 := Square{10, "Go_Sqr1"}
13         fmt.Println("Square sqr1 is    : ", sqr1)
14 
15         //initialize values by variable name in any order
16         sqr2 := Square{name: "Go_Sqr2", X: 15}
17         fmt.Println("Square sqr2 is    : ", sqr2)
18 
19         //get pointer to an instance with new keyword
20         ps := new(Square)
21 
22         //set value using . notation by dereferencing pointer
23         (*ps).X = 30
24 
25         //set value using . same as above
26         ps.name = "Go_Sqr3"
27 
28         fmt.Println("Square ps is      : ", *ps)
29         
30         ps1 := &sqr1
31         ps1.X = 22
32         fmt.Println("The new value of X: ", ps1.X)
33         fmt.Println("Square sqr1 is    : ", sqr1)
34 }

The output is:

Square sqr1 is    :  {10 Go_Sqr1}
Square sqr2 is    :  {15 Go_Sqr2}
Square ps is      :  {30 Go_Sqr3}
The new value of X:  22
Square sqr1 is    :  {22 Go_Sqr1}

Note: As seen above, you can get a pointer to a newly created struct instance using the new keyword. A pointer thus obtained, can be used with or without using the * operator to get variables within it.

Thus new(T) returns a pointer to a newly allocated zero value of type T. This is important to remember.

This means a user of the data structure can create one with new and get right to work.

Another example:

Program: struct_ptr.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 type Person struct {
 6 	name string
 7 	age  int
 8 }
 9 
10 func main() {
11 	fmt.Println(Person{"Kiran", 30})
12 	fmt.Println(Person{name: "Satish", age: 60})
13 
14 	s := Person{"Victor", 45}
15 	fmt.Println(s)
16 
17 	r := &Person{"Harry", 30} // Pointer
18 	fmt.Println(r)
19 	r.age = 33      // Changing the values
20 	fmt.Println(*r) // Pointer de-referencing
21 
22 	// Another example of Pointers
23 	p := &Person{}
24 	p.name = "Hulk"
25 	p.age = 10
26 	fmt.Println(*p)
27 }

The output is:

{Kiran 30}
{Satish 60}
{Victor 45}
&{Harry 30}
{Harry 33}
{Hulk 10}

An anonymous struct field

Program: struct4.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 type A struct {
 6         ax, ay int
 7 }
 8 type B struct {
 9         A
10         bx, by float64
11 }
12 
13 func main() {
14         b := B{A{1, 2}, 3.0, 4.0}
15         fmt.Println(b.ax, b.ay, b.bx, b.by)
16         fmt.Println(b.A)        
17 }

The output is:

1 2 3 4
{1 2}

Anonymous fields of any type

Any named type, or pointer to one, may be used in an anonymous field and it may appear at any location in the struct.

Program: struct5.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 type C struct {
 6         x float64
 7         int
 8         string
 9 }
10 
11 func main() {
12         c := C{3.5, 7, "hello"}
13         fmt.Println(c.x, c.int, c.string)
14 }

The output is:

3.5 7 hello

Now let us understand how to define a function on a struct.

A normal function that we name myFunc that takes no parameters and returns an int would be defined similar to the code snippet shown below:

1 func myFunc() int {
2         //code
3 }

A function like myFunc that takes no parameters and returns an int, but which is associated with a type which we call as myType would be defined similar to the code snippet shown below:

1 type myType struct{}
2 
3 func (f myType) myFunc() int {
4         //code
5 }

In between the keyword func and the name of the function (myFunc()) we have added a “receiver”. The receiver is like a parameter – it has a name and a type. In Go, a function which takes a receiver is usually called a method.

Let’s extend our earlier Square struct to add an Area function. This time we will define that the Area function works explicitly with the Square type:

Program: struct6.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 type Square struct {
 6         X    int
 7         name string
 8 }
 9 
10 func (s Square) Area() int {
11         return s.X * s.X
12 }
13 
14 func main() {
15         r1 := Square{5, "my_sqr"}
16         fmt.Println("Square is: ", r1)
17         fmt.Println("Square area is: ", r1.Area())
18 }

The output is:

Square is:  {5 my_sqr}
Square area is:  25

Let’s now modify the program stuct0.go to use structs.

Program: struct6a.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 type Rectangle struct {
 6         length, width float64
 7 }
 8 
 9 func (r Rectangle) Area() float64 {
10 	return r.length * r.width
11 }
12 
13 func (r Rectangle) Perimeter() float64 {
14 	return 2 * (r.length + r.width)
15 }
16 
17 func main() {
18 	r := Rectangle{4.5, 3.75}
19 
20 	area := r.Area()
21 	fmt.Println("Area is = ", area)
22 
23 	perimeter := r.Perimeter()
24 	fmt.Println("Perimeter is = ", perimeter)
25 }

The output is:

Area is =  16.875
Perimeter is =  16.5

12.1 What’s the difference between pointer and non-pointer method receivers?

We know that in Go, a function which takes a receiver is usually called a method.

func (s *MyStruct) pointerMethod() { } // method on pointer func (s MyStruct) valueMethod() { } // method on value

Simply stated: you can treat the receiver as if it was an argument being passed to the method. All the same reasons why you might want to pass by value or pass by reference apply.

Reasons why you would want to pass by reference as opposed to by value:

  • You want to actually modify the receiver (“read/write” as opposed to just “read”)
  • The struct is very large and a deep copy is expensive
  • Consistency: if some of the methods on the struct have pointer receivers, the rest should too. This allows predictability of behavior

If you need these characteristics on your method call, use a pointer receiver.

Here are even more rules of thumb2 to help you choose whether to use a value or pointer receiver.

Program: struct7.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 type Number struct {
 6         i int
 7         j int
 8 }
 9 
10 func (n Number) Same() {
11         n.i = 23
12         n.j = 47
13 }
14 
15 func (n *Number) Change() {
16         n.i = 23
17         n.j = 47
18 }
19 
20 func main() {
21 	n := &Number{0, 0}
22 	fmt.Println(n)
23 	n.Same()
24 	fmt.Println(n)
25 	n.Change()
26 	fmt.Println(n)
27 }

The output is:

&{0 0}
&{0 0}
&{23 47}

The method Same is defined with a non-pointer receiver and doesn’t change the values of the struct it is invoked on, and Change is defined with a pointer receiver, so it does change the values of the struct upon which it is invoked.

12.2 Solutions

Exercise 15 Solution3.

  1. http://en.wikipedia.org/wiki/Procedural_programming
  2. https://github.com/golang/go/wiki/CodeReviewComments#receiver-type
  3. https://play.golang.org/p/ya7p5kOvom

13. interface

An interface is a set of methods. To turn it around, the methods implemented by a concrete type such as a struct form the interface of that type.

Let’s focus on the method set aspect of interfaces first.

In Go, suppose you have an interface for a Dog:

1 type Dog interface {
2 	Woof()
3 }

Any struct that has a Woof method will implement the Dog interface implicitly and can be used as a Dog.

Program: intf1.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 type Dog interface {
 6 	Woof()
 7 }
 8 
 9 type Lassie struct {
10 }
11 
12 func (l Lassie) Woof() {
13 	fmt.Println("woof woof!")
14 }
15 
16 type Astro struct {
17 }
18 
19 func (a Astro) Woof() {
20         fmt.Println("WOOF WOOF!!")
21 }
22 
23 func main() {
24         var dog Dog
25         dog = Lassie{}
26         dog.Woof()
27 
28         dog = Astro{}
29         dog.Woof()
30 }

with output:

woof woof!
WOOF WOOF!!

If you have another struct, Cat, which doesn’t have a Woof method and you tried to use it as a Dog then you’ll get a compile time error:

Program: intf2.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 type Dog interface {
 6 	Woof()
 7 }
 8 
 9 type Lassie struct {
10 }
11 
12 func (l Lassie) Woof() {
13 	fmt.Println("woof woof!")
14 }
15 
16 type Astro struct {
17 }
18 
19 func (a Astro) Woof() {
20         fmt.Println("WOOF WOOF!!")
21 }
22 
23 type Cat struct {
24 }
25 
26 func (c Cat) Meow() {
27         fmt.Println("meow meow")
28 }
29 
30 func main() {
31         var dog Dog
32         dog = Lassie{}
33         dog.Woof()
34 
35         dog = Astro{}
36         dog.Woof()
37 
38         dog = Cat{}
39         dog.Woof()
40 }

with output:

cannot use Cat literal (type Cat) as type Dog in assignment:
Cat does not implement Dog (missing Woof method)

Earlier we had seen an example of a Square struct and an Area function:

Program: intf3.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 type Square struct {
 6         Width, Height int
 7 }
 8 
 9 func (s Square) Area() int {
10         return s.Width * s.Height
11 }
12 
13 func main() {
14         r1 := Square{5, 5}
15         fmt.Println("Square is: ", r1)
16         fmt.Println("Square area is: ", r1.Area())
17 }

with output:

Square is:  {5 5}
Square area is:  25

Note: Although not used here, it is idiomatic in Go for interface names to be suffixed with “-er” (like Positioner, Distancer).

Let us now abstract out the Area function into an interface called Geometry. Geometry is an interface and has a single function Area that returns an int as follows:

1 type Geometry interface {
2         Area() int
3 }

Let us write the full program:

Program: geometry.go
 1 package main
 2 
 3 import "fmt"
 4 
 5 type Square struct {
 6 	Width, Height int
 7 }
 8 
 9 type Geometry interface {
10 	Area() int
11 }
12 
13 // To implement an interface in Go, we just need to implement all the methods
14 // in the interface
15 func (s Square) Area() int {
16 	return s.Width * s.Height
17 }
18 
19 // If a variable has an interface type, then we can call methods that are in
20 // the named interface. Here is a generic measure function taking advantage of
21 // this to work on any Geometry.
22 func measure(g Geometry) {
23 	fmt.Println(g)
24 	fmt.Println(g.Area())
25 }
26 
27 func main() {
28 	s := Square{Width: 3, Height: 4}
29 
30 	// The Square struct type implements the Geometry interface so we can
31 	// use instances of these structs as arguments to measure.
32 	measure(s)
33 }

The output is:

{3 4}
12

Here’s an example1 of a simple Animal interface.

13.1 The interface{} type

It’s possible to define an interface without any methods. Such an interface is known as an empty interface, and it’s denoted by interface{}. Since there are no methods, all types will satisfy this interface.

That means if you write a function that takes an interface{} value as a parameter, you can supply that function with any value. So, this function:

1 func DoSomething(v interface{}) {
2         // ...
3 }

will accept any parameter whatsoever.

Here’s where it gets confusing: inside of the DoSomething function, what is v’s type? Beginners are led to believe that “v is of any type”, but that is wrong. v is not of any type; it is of interface{} type. Wait, what? When passing a value into the DoSomething function, the Go runtime will perform a type conversion (if necessary), and convert the value to an interface{} value. All values have exactly one type at runtime, and v’s one static type is interface{}.

This should leave you wondering: ok, so if a conversion is taking place, what is actually being passed into a function that takes an interface{} value?

If you understand that an interface value is two words wide and it contains a pointer to the underlying data, that’s typically enough to avoid common pitfalls.

This topic is adapted from blog posts this2 and this3

13.2 Solutions

Exercise 16 Solution4.

  1. http://play.golang.org/p/yGTd4MtgD5
  2. http://jordanorelli.tumblr.com/post/32665860244/how-to-use-interfaces-in-go
  3. http://theburningmonk.com/2015/05/why-i-like-golang-interfaces/
  4. http://play.golang.org/p/VABl9UNTOs

14. Error

It is idiomatic in Go to use the error interface type as the return type for any error that is going to be returned from a function or method. This interface is used by all the functions and methods in the standard library that return errors.

Go code uses error values to indicate an abnormal state. For example, the os.Open function returns a non-nil error value when it fails to open a file.

func Open(name string) (file *File, err error)

The following code uses os.Open to open a file. If an error occurs it calls log.Fatal to print the error message and stop.

1 f, err := os.Open("filename.ext")
2 if err != nil {
3         log.Fatal(err)
4 }
5 // do something with the open *File f

Handling errors that are returned from functions and methods starts by checking if the returned interface value of type error is not nil. Thus in the above code, the value of the err variable is compared to the value of nil. If the value is not nil, then there was an error.

In Go, error handling is important. The language’s design and conventions encourage you to explicitly check for errors where they occur (as distinct from the convention in other languages of throwing exceptions and sometimes catching them). In some cases this makes Go code verbose.

15. io, os and net/http - Getting started

15.1 io

Usage: import "io"

Package io provides basic interfaces to I/O primitives.

func Copy(dst Writer, src Reader) (written int64, err error)

Copy copies from src to dst until either EOF is reached on src or an error occurs. It returns the number of bytes copied and the first error encountered while copying, if any.

A successful Copy returns err == nil, not err == EOF. Because Copy is defined to read from src until EOF, it does not treat an EOF from Read as an error to be reported.

15.2 os

Usage: import "os"

Documentation1

Package os provides a platform-independent interface to operating system functionality.

Stdin, Stdout, and Stderr are open Files pointing to the standard input, standard output, and standard error file descriptors.

Hence os.Stdout will write to the standard output.

15.3 TCP and net/http

Networking usually implies TCP/IP, the way in which millions of machines communicate back and forth across the Internet. Network communication is conceptualized at different layers - data link, network, transport and application. The application layer is the world of telnet, FTP, email protocols, and much more.

15.3.1 Basic Networking

Let us talk a little bit about basic networking.

Our discussion of networking focuses on both sides of a client-server relationship. The client requests that some action be performed, and the server performs the action and responds to the client. A dedicated server spends its lifetime waiting for messages and answering them. A common implementation of the request-response model is between World Wide Web browsers and World Wide Web servers. When a user selects a Web site to browse through a browser (the client application), a request is sent to the appropriate Web server (the server application). The server normally responds to the client by sending an appropriate HTML Web page.

15.3.2 Port

A port is not a physical device, but an abstraction to facilitate communication between a server and a client.

Ports are described by a 16-bit integer value. Hence, a machine can have a maximum of 65536 port numbers (ranging from 0 to 65535). The port numbers are divided into three ranges: the Well Known Ports, the Registered Ports, and the Dynamic and/or Private Ports. The Well Known Ports are those from 0 through 1023 (for example, port no. 80 is for http, port no. 25 is for smtp and so on). The Registered Ports are those from 1024 through 49151. The Dynamic and/or Private Ports are those from 49152 through 65535.

15.3.3 Internet Addresses

These are the numerical host addresses that consist of four bytes such as 132.163.4.102. The IP address 127.0.0.1 (localhost) is a special address, called the local loopback address, which denotes the local machine.

15.3.4 net/http

Usage: import "net/http"

Package http provides HTTP client and server implementations.

Get, Head, Post, and PostForm make HTTP (or HTTPS) requests.

func Get(url string) (resp *Response, err error)

Get issues a GET to the specified URL. An error is returned if there was an HTTP protocol error. When err is nil, resp always contains a non-nil resp.Body. Caller should close resp.Body when done reading from it.

The Response2 structure among others has the field StatusCode which is an int (e.g. 200), a field Body that represents the response body and Close which should be called by the caller to close the Body.

The http.StatusOK is a constant with the value of 200.

An example:

 1 package main
 2 
 3 import (
 4 	"io"
 5 	"log"
 6 	"net/http"
 7 	"os"
 8 )
 9 
10 func main() {
11 	resp, err := http.Get("http://www.google.com/robots.txt")
12 	if err != nil {
13 		log.Fatal(err)
14 	}
15 
16 	defer resp.Body.Close()
17 
18 	if resp.StatusCode != http.StatusOK {
19 		log.Fatal(resp.Status)
20 	}
21 
22 	_, err = io.Copy(os.Stdout, resp.Body)
23 	if err != nil {
24 		log.Fatal(err)
25 	}
26 }
  1. http://golang.org/pkg/os/
  2. http://golang.org/pkg/net/http/#Response

16. Random Numbers

Go’s math/rand package provides pseudo-random number generation.

Random numbers are generated by a Source. Top-level functions, such as Float64 and Int, use a default shared Source that produces a deterministic sequence of values each time a program is run. Use the Seed function to initialize the default Source if different behavior is required for each run. The default Source is safe for concurrent use by multiple goroutines.

Usage: import "math/rand"

func Intn(n int) int

Intn returns, as an int, a non-negative pseudo-random number in [0,n) from the default Source. It panics if n <= 0.

func Float64() float64

Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from the default Source.

Let us look at an example:

 1 package main
 2 
 3 import (
 4         "fmt"
 5         "math/rand"
 6 )
 7 
 8 func main() {
 9         fmt.Println(rand.Intn(500))
10         fmt.Println(rand.Float64())
11 }

In the above program, rand.Intn returns a random int n, 0 <= n < 500.

When you run the above program the output is always the same. I got 81 and 0.9405090880450124 no matter how many times I ran the program.

To make the pseudo-random generator deterministic, give it a well-known seed. To do that let us look at:

func NewSource(seed int64) Source

NewSource returns a new pseudo-random Source seeded with the given value.

Let us modify our above program as:

 1 package main
 2 
 3 import (
 4         "fmt"
 5         "math/rand"
 6 )
 7 
 8 func main() {
 9         fmt.Print(rand.Intn(500))
10         fmt.Println(rand.Float64())
11 
12         s1 := rand.NewSource(21)
13         r1 := rand.New(s1)
14         fmt.Println(r1.Intn(500))
15         fmt.Println(r1.Float64())
16 }

Now the output I get is always:

810.9405090880450124
3000.8375676569149538

17. File Handling

17.1 Package ioutil

Usage: import "io/ioutil"

Documentation: ioutil1

The function ioutil.ReadFile(filename string) reads the entire contents of the file filename into memory.

Type and store the following program in the same folder where you had written hello.go:

Program: read_file_ioutil.go
 1 package main
 2 
 3 import (
 4 	"fmt"
 5 	"io/ioutil"
 6 	"log"
 7 )
 8 
 9 func check(e error) {
10 	if e != nil {
11 		log.Fatal(e)
12 	}
13 }
14 
15 func main() {
16 	dat, err := ioutil.ReadFile("hello.go")
17 	check(err)
18 	fmt.Print(string(dat))
19 }

The program will output the contents of the file hello.go.

func ReadFile(filename string) ([]byte, error)

ReadFile reads the file named by filename and returns the contents. A successful call returns err == nil, not err == EOF. Because ReadFile reads the whole file, it does not treat an EOF from Read as an error to be reported.

17.2 Package os

Usage: import "os"

Documentation: http://golang.org/pkg/os/

Package os provides a platform-independent interface to operating system functionality.

Let us look at some programs in this section.

17.2.1 read_file_os1.go

First write the program read_file_os1.go in the same folder where you had written hello.go as follows:

Program: read_file_os1.go
 1 package main
 2 
 3 import (
 4 	"fmt"
 5 	"log"
 6 	"os"
 7 )
 8 
 9 func check(e error) {
10 	if e != nil {
11 		log.Fatal(e)
12 	}
13 }
14 
15 func main() {
16 	file, err := os.Open("hello.go") // For read access
17 	check(err)
18 	defer file.Close()
19 
20 	// get the file size
21 	stat, err := file.Stat()
22 	check(err)
23 
24 	// read the file
25 	bs := make([]byte, stat.Size())
26 	_, err = file.Read(bs)
27 	check(err)
28 
29 	str := string(bs) // type string
30 	fmt.Println(str)
31 }

The above program is an example of how to read the contents of a file and display them on the terminal.

17.2.1.1 Stat
1 func (f *File) Stat() (fi FileInfo, err error)

Stat returns the FileInfo structure describing file. If there is an error, it will be of type *PathError.

17.2.1.2 FileInfo

A FileInfo describes a file and is returned by Stat and Lstat.

Here’s the FileInfo interface:

1 type FileInfo interface {
2         Name() string       // base name of the file
3         Size() int64        // length in bytes for regular files;
4                             // system-dependent for others
5         Mode() FileMode     // file mode bits
6         ModTime() time.Time // modification time
7         IsDir() bool        // abbreviation for Mode().IsDir()
8         Sys() interface{}   // underlying data source (can return nil)
9 }

Observe that Size() gives us the length in bytes for regular files.

17.2.2 read_file_os2.go

Next write the second program read_file_os2.go in the same folder where you had written hello.go as follows:

Program: read_file_os2.go
 1 package main
 2 
 3 import (
 4 	"fmt"
 5 	"log"
 6 	"os"
 7 )
 8 
 9 func check(e error) {
10 	if e != nil {
11 		log.Fatal(e)
12 	}
13 }
14 
15 func main() {
16 	file, err := os.Open("hello.go") // For read access
17 	check(err)
18 	defer file.Close()
19 
20 	//The file's data can then be read into a slice
21 	//of bytes. Read and Write take their byte counts
22 	//from the length of the argument slice.
23 	//Read some bytes from the beginning of
24 	//the file. Allow up to 5 to be read but
25 	//also note how many actually were read.
26 	slice1 := make([]byte, 5)
27 	n1, err := file.Read(slice1)
28 	check(err)
29 	fmt.Printf("%d bytes: %s\n", n1, string(slice1))
30 
31 	//You can also Seek to a known location in
32 	//the file and Read from there.
33 	o2, err := file.Seek(6, 0)
34 	check(err)
35 	slice2 := make([]byte, 2)
36 	n2, err := file.Read(slice2)
37 	check(err)
38 	fmt.Printf("%d bytes @ %d: %s\n", n2, o2, string(slice2))
39 }

Part of the output is shown below:

5 bytes: // Si
2 bytes @ 6: gl
17.2.2.1 seek function:
1 func (f *File) Seek(offset int64, whence int) (ret int64, err error)

Seek sets the offset for the next Read or Write on file to offset, interpreted according to whence: 0 means relative to the origin of the file, 1 means relative to the current offset, and 2 means relative to the end. It returns the new offset and an error, if any.

Note: There is no built-in rewind, but Seek(0, 0) accomplishes this.

17.2.3 write_file_os.go

The next program write_file_os.go is an example on how we can create a file:

Program: write_file_os.go
 1 package main
 2 
 3 import (
 4 	"log"
 5 	"os"
 6 )
 7 
 8 func check(e error) {
 9 	if e != nil {
10 		log.Fatal(e)
11 	}
12 }
13 
14 func main() {
15 	file, err := os.Create("test.txt")
16 	check(err)
17 	defer file.Close()
18 
19 	file.WriteString("test")
20 
21 	//Issue a Sync to flush writes
22 	//to stable storage.
23 	file.Sync()
24 }
17.2.3.1 Create
1 func Create(name string) (file *File, err error)

Create creates the named file mode 0666 (before umask), truncating it if it already exists. If successful, methods on the returned File can be used for I/O; the associated file descriptor has mode O_RDWR. If there is an error, it will be of type *PathError.

17.2.3.2 WriteString
1 func (f *File) WriteString(s string) (ret int, err error)

WriteString writes the contents of string s.

17.2.4 read_dir_os.go

The next program read_dir_os.go is an example on how to get the contents of a directory:

Program: read_dir_os.go
 1 package main
 2 
 3 import (
 4 	"fmt"
 5 	"log"
 6 	"os"
 7 )
 8 
 9 func check(e error) {
10 	if e != nil {
11 		log.Fatal(e)
12 	}
13 }
14 
15 func main() {
16 	dir, err := os.Open(".")
17 	check(err)
18 	defer dir.Close()
19 
20 	fileInfos, err := dir.Readdir(-1)
21 	check(err)
22 	for _, fi := range fileInfos {
23 		fmt.Println(fi.Name())
24 	}
25 }
17.2.4.1 Readdir
1 func (f *File) Readdir(n int) (fi []FileInfo, err error)

Readdir reads the contents of the directory associated with file and returns a slice of up to n ``FileInfo values, in directory order. Subsequent calls on the same file will yield further FileInfos.

If n > 0, Readdir returns at most n FileInfo structures. In this case, if Readdir returns an empty slice, it will return a non-nil error explaining why. At the end of a directory, the error is io.EOF.

If n <= 0, Readdir returns all the FileInfo from the directory in a single slice. In this case, if Readdir succeeds (reads all the way to the end of the directory), it returns the slice and a nil error. If it encounters an error before the end of the directory, Readdir returns the FileInfo read until that point and a non-nil error.

17.2.4.2 Name()

Name() returns a string which is the base name of the file.

17.3 Package bufio

Usage: import "bufio"

Documentation: bufio

Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer object, creating another object (Reader or Writer) that also implements the interface but provides buffering and some help for textual I/O.

Let us write a program read_bufio.go as follows:

Program: read_bufio.go
 1 package main
 2 
 3 import (
 4 	"bufio"
 5 	"fmt"
 6 	"log"
 7 	"os"
 8 )
 9 
10 func check(e error) {
11 	if e != nil {
12 		log.Fatal(e)
13 	}
14 }
15 
16 func main() {
17 	file, err := os.Open("hello.go")
18 	check(err)
19 	defer file.Close()
20 
21 	reader := bufio.NewReader(file)
22 
23 	b4, err := reader.Peek(5)
24 	check(err)
25 	fmt.Printf("5 bytes: %s\n", string(b4))
26 }

17.3.1 NewReader

1 func NewReader(rd io.Reader) *Reader

NewReader returns a new Reader whose buffer has the default size.

17.3.2 Peek

1 func (b *Reader) Peek(n int) ([]byte, error)

Peek returns the next n bytes without advancing the reader. The bytes stop being valid at the next read call. If Peek returns fewer than n bytes, it also returns an error explaining why the read is short. The error is ErrBufferFull if n is larger than b’s buffer size.

Now let us write a program write_bufio.go as follows:

Program: write_bufio.go
 1 package main
 2 
 3 import (
 4 	"bufio"
 5 	"fmt"
 6 	"log"
 7 	"os"
 8 )
 9 
10 func check(e error) {
11 	if e != nil {
12 		log.Fatal(e)
13 	}
14 }
15 
16 func main() {
17 	f, err := os.Create("test2.txt")
18 	check(err)
19 	defer f.Close()
20 
21 	w := bufio.NewWriter(f)
22 	n4, err := w.WriteString("buffered\n")
23 	fmt.Printf("wrote %d bytes\n", n4)
24 
25 	w.Flush()
26 }

The output is:

wrote 9 bytes

17.3.3 NewWriter

1 func NewWriter(wr io.Writer) *Writer

NewWriter returns a new Writer whose buffer has the default size.

Original file contents:

text text text text text
text text text text text
text text word text text
text text text text text
text text text text text

Modified file contents:

text text text text text
text text text text text
text text inserted word text text
text text text text text
text text text text text

17.4 Solutions

Exercise 17 Solution:

Exercise 18 solution:

Fun2
Fun2

WAIT… If you have liked the course so far, I am confident that you will like the latter part of the course too. This is where the fun begins.

Fun4 Glad to have you back…

  1. http://golang.org/pkg/io/ioutil/
  2. http://rubylearning.com/data/song.mp3

18. JSON and Go

18.1 JSON

JSON stands for JavaScript Object Notation.

JSON is syntax for storing and exchanging text information, much like XML. JSON is smaller than XML, and faster and easier to parse. JSON is language independent. Here’s an example:

1 {
2 "employees": [
3 { "firstName":"John" , "lastName":"Doe" },
4 { "firstName":"Anna" , "lastName":"Smith" },
5 { "firstName":"Peter" , "lastName":"Jones" }
6 ]
7 }

The employee object is an array of 3 employee records (objects).

JSON data is written as name/value pairs. A name/value pair consists of a field name (in double quotes), followed by a colon and followed by a value:

"firstName" : "Satish"

JSON values can be:

  • A number (integer or floating point)
  • A string (in double quotes)
  • A Boolean (true or false)
  • An array (in square brackets)
  • An object (in curly brackets)
  • null

JSON objects are written inside curly brackets, Objects can contain multiple name/values pairs:

{ "firstName":"Satish" , "lastName":"Talim" }

18.2 Package json

Usage: import "encoding/json"

Package json implements encoding and decoding of JSON objects.

18.2.1 Encoding

To encode JSON data we use the Marshal function.

func Marshal(v interface{}) ([]byte, error)

Let’s look at an example.

Program: json1.go
 1 package main
 2 
 3 import (
 4         "encoding/json"
 5         "fmt"
 6 )        
 7 
 8 type User struct {
 9 	UserName string
10 	EmailID  string
11 	Password  string
12 }
13 
14 func main() {
15 	u := User{UserName: "IndianGuru", EmailID: "satishtalim@gmail.com", Password: "password"}
16 	m, _ := json.Marshal(u)
17 	fmt.Println(string(m))
18 }

The output is:

{"UserName":"IndianGuru","EmailID":"satishtalim@gmail.com","Password":"password"}

In the above program we have a simple struct, we create a new instance of this struct and encode it.

18.2.2 Struct tags

1 type Person struct {
2         UserName string `json:"user_name"`
3         EmailID  string
4         Password string `json:"-"`
5 }

When we use the Marshal function on a struct instance it produces JSON.

In the above example, a field appears in JSON as key “user_name” and the Password field is ignored by this package.

In the previous example json1.go the password got printed. However, we don’t want to print the password. Here’s the changed code:

Program: json2.go
 1 package main
 2 
 3 import (
 4         "encoding/json"
 5         "fmt"
 6 )        
 7 
 8 type User struct {
 9 	UserName string `json:"user_name"`
10 	EmailID  string
11 	Password string `json:"-"`
12 }
13 
14 func main() {
15 	u := User{UserName: "IndianGuru", EmailID: "satishtalim@gmail.com", Password: "password"}
16 	m, _ := json.Marshal(u)
17 	fmt.Println(string(m))
18 }

The output is:

{"user_name":"IndianGuru","EmailID":"satishtalim@gmail.com"}

What if I don’t want to show the UserName if it is empty? Here’s the modified code:

Program: json3.go
 1 package main
 2 
 3 import (
 4         "encoding/json"
 5         "fmt"
 6 )        
 7 
 8 type User struct {
 9 	UserName string `json:"first_name,omitempty"`
10 	EmailID  string
11 	Password string `json:"-"`
12 }
13 
14 func main() {
15 	u := User{UserName: "", EmailID: "", Password: "password"}
16 	m, _ := json.Marshal(u)
17 	fmt.Println(string(m))
18 }

The output is:

{"EmailID":""}

The JSON parser also accepts a flag in the tag to let it know what to do if the field is empty. The omitempty flag tells it to not include the JSON value in the output if it’s the “zero-value” for that type.

The “zero-value” for numbers is 0, for strings it’s the empty string, for maps, slices and pointers it’s nil. This is how you include the omitempty flag.

1 type MyStruct struct {
2         SomeField string `json:"some_field,omitempty"`
3 }

Notice that the flag goes inside the quotes.

If the SomeField was an empty string, and you converted it to JSON, some_field wouldn’t be included in the output at all.

What if I want to retain the field name EmailID and at the same time use the omitempty flag? Here’s the modified code:

Program: json4.go
 1 package main
 2 
 3 import (
 4         "encoding/json"
 5         "fmt"
 6 )        
 7 
 8 type User struct {
 9 	UserName string `json:"first_name,omitempty"`
10 	EmailID  string `json:",omitempty"`
11 	Password string `json:"-"`
12 }
13 
14 func main() {
15 	u := User{UserName: "", EmailID: "", Password: "password"}
16 	m, _ := json.Marshal(u)
17 	fmt.Println(string(m))
18 }

The output is:

{}

Let’s look at another example:

Program: json5.go
 1 package main
 2 
 3 import (
 4         "encoding/json"
 5         "fmt"
 6         "os"
 7 )
 8 
 9 type Response1 struct {
10         Page   int
11         Conf []string
12 }
13 
14 type Response2 struct {
15     Page   int      `json:"page"` // Field appears in JSON as key "page"
16     Conf []string   `json:"conf"` // Field appears in JSON as key "conf"
17 }
18 
19 func main() {
20         // encoding basic data types to JSON strings
21         bolB, _ := json.Marshal(false)
22         fmt.Println(string(bolB))
23 
24         intB, _ := json.Marshal(3)
25         fmt.Println(string(intB))
26 
27         fltB, _ := json.Marshal(87.23)
28         fmt.Println(string(fltB))
29 
30         strB, _ := json.Marshal("go class")
31         fmt.Println(string(strB))
32 
33         // encoding a slice
34         slcD := []string{"gophercon", "gopherconindia", "go china"}
35         slcB, _ := json.Marshal(slcD)
36         fmt.Println(string(slcB))
37 
38         // encoding a map
39         // the map's key type must be a string
40         mapD := map[string]int{"pune": 5, "franklin": 7}
41         mapB, _ := json.Marshal(mapD)
42         fmt.Println(string(mapB))
43 
44         // The JSON package can automatically encode your
45         // custom data types. It will only include exported
46         // fields in the encoded output and will by default
47         // use those names as the JSON keys.
48         res1D := &Response1{
49                 Page: 1,
50                 Conf: []string{"gophercon", "gopherconindia", "go china"}}
51         res1B, _ := json.Marshal(res1D)
52         fmt.Println(string(res1B))
53 
54         // You can use tags on struct field declarations to
55         // customize the encoded JSON key names. Check the 
56         // definition of Response2 above to see an example of
57         // such tags.
58         res2D := &Response2{
59                 Page: 1,
60                 Conf: []string{"gophercon", "gopherconindia", "go china"}}
61         res2B, _ := json.Marshal(res2D)
62         fmt.Println(string(res2B))
63 }

The output is:

false
3
87.23
"go class"
["gophercon","gopherconindia","go china"]
{"franklin":7,"pune":5}
{"Page":1,"Conf":["gophercon","gopherconindia","go china"]}
{"page":1,"conf":["gophercon","gopherconindia","go china"]}

18.2.3 Decoding

To decode JSON data we use the Unmarshal function.

func Unmarshal(data []byte, v interface{}) error

We must first create a place where the decoded data will be stored.

var m Message

and call json.Unmarshal, passing it a []byte of JSON data and a pointer to m.

err := json.Unmarshal(b, &m)

If b contains valid JSON that fits in m, after the call err will be nil and the data from b will have been stored in the struct m, as if by an assignment like:

1 m = Message {
2             Name: "Alice",
3             Body: "Hello",
4             Time: 1294706395881547000,
5 }

How does Unmarshal identify the fields in which to store the decoded data? For a given JSON key “Foo”, Unmarshal will look through the destination struct’s fields to find (in order of preference):

  • An exported field with a tag of “Foo” (see the Go spec for more on struct tags),
  • An exported field named “Foo”, or
  • An exported field named “FOO” or “FoO” or some other case-insensitive match of “Foo”.

What happens when the structure of the JSON data doesn’t exactly match the Go type?

1 b := []byte(`{"Name":"Bob","Food":"Pickle"}`)
2 var m Message
3 err := json.Unmarshal(b, &m)

Unmarshal will decode only the fields that it can find in the destination type. In this case, only the Name field of m will be populated, and the Food field will be ignored. This behavior is particularly useful when you wish to pick only a few specific fields out of a large JSON blob. It also means that any unexported fields in the destination struct will be unaffected by Unmarshal.

Unmarshal stores in the interface value: map[string]interface{}, for JSON objects.

Here’s an example:

Program: json6.go
 1 package main
 2 
 3 import (
 4         "encoding/json"
 5         "fmt"
 6 )
 7 
 8 type Response2 struct {
 9     Page   int      `json:"page"`
10     Conf []string   `json:"conf"`
11 }
12 
13 func main() {
14         // We can also decode JSON into custom data types. 
15         // This has the advantages of adding additional 
16         // type-safety to our programs and eliminating the
17         // need for type assertions when accessing the decoded data.
18         // `Unmarshal` will decode only the fields that it can find 
19         // in the destination type. In this case, only the Page and
20         // Conf field of res will be populated, and the Food field
21         // will be ignored.
22         str := `{"page": 1, "conf": ["gophercon", "gopherconindia"], "Food":"Pickle"}`
23         res := &Response2{}
24         json.Unmarshal([]byte(str), &res)
25         fmt.Println(res)
26         fmt.Println(res.Conf[0])
27 }

The output is:

&{1 [gophercon gopherconindia]}
gophercon

18.2.4 Streaming Encoders and Decoders

The json package provides Decoder and Encoder types to support the common operation of reading and writing streams of JSON data. The NewDecoder and NewEncoder functions wrap the io.Reader and io.Writer interface types.

func NewDecoder(r io.Reader) *Decoder

func NewEncoder(w io.Writer) *Encoder

func (enc *Encoder) Encode(v interface{}) error

Encode1 writes the JSON encoding of v to the stream, followed by a newline character.

func (dec *Decoder) Decode(v interface{}) error

Decode2 reads the next JSON-encoded value from its input and stores it in the value pointed to by v.

Previously, to encode JSON data we had used the Marshal function.

Program: json1.go
 1 package main
 2 
 3 import (
 4         "encoding/json"
 5         "fmt"
 6 )        
 7 
 8 type User struct {
 9 	UserName string
10 	EmailID  string
11 	Password  string
12 }
13 
14 func main() {
15 	u := User{UserName: "IndianGuru", EmailID: "satishtalim@gmail.com", Password: "password"}
16 	m, _ := json.Marshal(u)
17 	fmt.Println(string(m))
18 }

The output was:

{"UserName":"IndianGuru","EmailID":"satishtalim@gmail.com","Password":"password"}

Let’s rewrite the above program using json.NewEncoder as follows:

Program: json7.go
 1 package main
 2 
 3 import (
 4         "encoding/json"
 5         "log"
 6         "os"
 7 )        
 8 
 9 type User struct {
10 	UserName string
11 	EmailID  string
12 	Password  string
13 }
14 
15 func main() {
16 	u := User{UserName: "IndianGuru", EmailID: "satishtalim@gmail.com", Password: "password"}
17 	
18 	// Replace the following lines of json1.go
19 	// m, _ := json.Marshal(u)
20 	// fmt.Println(string(m))
21 	// with:
22 	enc := json.NewEncoder(os.Stdout)
23 	if err := enc.Encode(u); err != nil {
24             log.Println(err)
25         }
26 }

The output is the same as before:

{"UserName":"IndianGuru","EmailID":"satishtalim@gmail.com","Password":"password"}

These Encoder and Decoder types can be used in a broad range of scenarios, such as reading and writing to HTTP connections, WebSockets, or files.

18.3 A Fun, Weather Forecast Go Web App

We shall build a fun Go app that displays the current weather forecast for a given city.

18.3.1 Register for an account at Forecast for Developers

Go to https://developer.forecast.io/register3 and register for an account. We shall use their free plan that allows us to use 1000 calls to their API per day. As such, there is no need to enter your credit card details. Also, this page gives you your very own API key that you will use in your program.

18.3.1.1 Study the API documentation

We need to read thro’ the API documentation4 of the Forecast for Developers.

Very briefly:

The Forecast Call

https://api.forecast.io/forecast/APIKEY/LATITUDE,LONGITUDE?units=ca

APIKEY should be your API key as mentioned above. LATITUDE and LONGITUDE should be the geographic coordinates of a location in decimal degrees.

The response will be a JSON-formatted object with the following properties defined:

  • latitude: The requested latitude.
  • longitude: The requested longitude.
  • timezone: The timezone name for the requested location (e.g. America/New_York).
  • offset: The current timezone offset in hours from GMT.
  • currently: A data point (see below) containing the current weather conditions at the requested location.

The following JSON Schema of the API is very informative - forecast.json5

Data Points

A data point object represents the various weather phenomena occurring at a specific instant of time, and has many varied properties. All of these properties (except time) are optional, and will only be set if we have that type of information for that location and time.

The following JSON Schema of the API is very informative - datapoint.json6

We shall use the two schema (datapoint.json and forecast.json) in our program.

Let us define our structs DataPoint and Forecast based on these two schema as follows:

 1 type DataPoint struct {
 2         Time                   float64
 3         Summary                string
 4         Icon                   string
 5         SunriseTime            float64
 6         SunsetTime             float64
 7         PrecipIntensity        float64
 8         PrecipIntensityMax     float64
 9         PrecipIntensityMaxTime float64
10         PrecipProbability      float64
11         PrecipType             string
12         PrecipAccumulation     float64
13         Temperature            float64
14         TemperatureMin         float64
15         TemperatureMinTime     float64
16         TemperatureMax         float64
17         TemperatureMaxTime     float64
18         DewPoint               float64
19         WindSpeed              float64
20         WindBearing            float64
21         CloudCover             float64
22         Humidity               float64
23         Pressure               float64
24         Visibility             float64
25         Ozone                  float64
26 }
27 
28 type Forecast struct {
29         Latitude  float64
30         Longitude float64
31         Timezone  string
32         Offset    float64
33         Currently DataPoint
34         Junk      string
35 }

Understanding url query string

A query string is a part of an URL that contains data that can be passed to web applications. This data needs to be encoded, and this encoding is done using url.QueryEscape. It performs what is also commonly called URL encoding7.

1 // addr is a string which contains our address
2 addr := "Pune,India"
3 
4 // QueryEscape escapes the addr string so
5 // it can be safely placed inside a URL query
6 safeAddr := url.QueryEscape(addr)
7 fmt.Println(safeAddr) // Pune%2CIndia

With url.QueryEscape our address “Pune,India” becomes “Pune%2CIndia” where %2C is the ASCII keycode in hexadecimal for a comma (,).

The Google Geocoding API

We shall use The Google Geocoding API8 to help us convert addresses (like “1600 Amphitheatre Parkway, Mountain View, CA”) into geographic coordinates (like latitude 37.423021 and longitude -122.083739).

To access the Geocoding API over HTTP, use:

http://maps.googleapis.com/maps/api/geocode/output?parameters

where output may be either of the following values:

  • json (recommended) indicates output in JavaScript Object Notation (JSON)
  • xml indicates output as XML

Some parameters are required while some are optional. As is standard in URLs, parameters are separated using the ampersand (&) character.

Required parameters in a geocoding request:

address — The street address that you want to geocode, in the format used by the national postal service of the country concerned. Additional address elements such as business names and unit, suite or floor numbers should be avoided.

We are not using any optional parameters in our geocoding request.

1 // Geocoding API
2 fullUrl := fmt.Sprintf("http://maps.googleapis.com/maps/api/geocode/json?address=%s", safe\
3 Addr)
4 fmt.Println(fullUrl)

The output is:

http://maps.googleapis.com/maps/api/geocode/json?address=Pune%2C+India

In your browser, open the site http://maps.googleapis.com/maps/api/geocode/json?address=Pune%2C+India the browser output is a huge blob of JSON. This may be difficult to look at in the browser, unless you have the JSONView plugin installed. These extensions are available for Firefox9 and Chrome10. With the extension installed you should be able to see a better view of the JSON returned.

Build the http request

func NewRequest(method, urlStr string, body io.Reader) (*Request, error)

NewRequest11 returns a new Request given a method, URL, and an optional body.

1 // Build the http request
2 req, err1 := http.NewRequest("GET", fullUrl, nil)
3 check(err1, "NewRequest:")

Also, we write a check function that checks for errors, if any:

1 func check(e error, str string) {
2         if e != nil {
3                 log.Fatal(str, " ", e)
4                 return
5         }
6 }

Create a Client

For control over HTTP client headers, redirect policy, and other settings, create a Client12. A Client is an HTTP client:

client := &http.Client{}

Send the request via a client

func (c *Client) Do(req *Request) (resp *Response, err error)

Do sends an HTTP request and returns an HTTP response.

1 resp, err2 := client.Do(req)
2 check(err2, "Do:")
3 
4 // Callers should close resp.Body
5 // when done reading from it
6 // Defer the closing of the body
7 defer resp.Body.Close()

Create a Response struct

Observe the JSON output when you open the site http://maps.googleapis.com/maps/api/geocode/json?address=Pune%2C+India in your browser. There is a results array, within which there is geometry, then location which finally contains lat and lng.

Therefore let’s define our struct as follows:

 1 type Response struct {
 2     Results []struct {
 3         Geometry struct {
 4             Location struct {
 5                 Lat float64
 6                 Lng float64
 7             }
 8         }
 9     }
10 }

Use a streaming Decoder

1 // Use json.Decode for reading streams of JSON data
2 if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
3         log.Println(err)
4 }

Extract the latitude and logitude

1 // lat, lng as float64
2 lat := res.Results[0].Geometry.Location.Lat
3 lng := res.Results[0].Geometry.Location.Lng

Use the Forecast API

Declare a global constant APIKey as: const APIKey string = "yourapikey"

safeLatLng := url.QueryEscape(fmt.Sprintf("%.13f,%.13f", lat, lng)) url := fmt.Sprintf("https://api.forecast.io/forecast/%s/%s?units=ca", APIKey, safeLatLng)

  • Remember to replace APIKey above with your actual api key.
  • %.13f is used to convert float64 to a string
  • ?units=ca - the API request was optionally modified through the use of query parameter units=ca will return temperatures in degrees Celsius.

Use http.Get

func Get(url string) (resp *Response, err error)

Get14 issues a GET to the specified URL.

1 resp, err := http.Get(url)
2 check(err, "Get:")
3 defer resp.Body.Close()

Use the Forecast struct to get the results

1 var f Forecast
2 if err := json.NewDecoder(resp.Body).Decode(&f); err != nil {
3         log.Println(err)
4 }
5 
6 fmt.Println("The Weather at ", addr)
7 fmt.Println("Timezone = ", f.Timezone)
8 fmt.Println("Temp in Celsius = ", f.Currently.Temperature)
9 fmt.Println("Summary = ", f.Currently.Summary)

Here’s the full program:

Program: weather.go
  1 package main
  2 
  3 import (
  4 	"encoding/json"
  5 	"fmt"
  6 	"log"
  7 	"net/http"
  8 	"net/url"
  9 )
 10 
 11 type DataPoint struct {
 12 	Time                   float64
 13 	Summary                string
 14 	Icon                   string
 15 	SunriseTime            float64
 16 	SunsetTime             float64
 17 	PrecipIntensity        float64
 18 	PrecipIntensityMax     float64
 19 	PrecipIntensityMaxTime float64
 20 	PrecipProbability      float64
 21 	PrecipType             string
 22 	PrecipAccumulation     float64
 23 	Temperature            float64
 24 	TemperatureMin         float64
 25 	TemperatureMinTime     float64
 26 	TemperatureMax         float64
 27 	TemperatureMaxTime     float64
 28 	DewPoint               float64
 29 	WindSpeed              float64
 30 	WindBearing            float64
 31 	CloudCover             float64
 32 	Humidity               float64
 33 	Pressure               float64
 34 	Visibility             float64
 35 	Ozone                  float64
 36 }
 37 
 38 type Forecast struct {
 39 	Latitude  float64
 40 	Longitude float64
 41 	Timezone  string
 42 	Offset    float64
 43 	Currently DataPoint
 44 	Junk      string
 45 }
 46 
 47 type Response struct {
 48 	Results []struct {
 49 		Geometry struct {
 50 			Location struct {
 51 				Lat float64
 52 				Lng float64
 53 			}
 54 		}
 55 	}
 56 }
 57 
 58 // Replace the text `yourapikey` below with your actual api key
 59 const APIKey string = "yourapikey"
 60 
 61 func main() {
 62 	Get()
 63 }
 64 
 65 func check(e error, str string) {
 66 	if e != nil {
 67 		log.Fatal(str, " ", e)
 68 		return
 69 	}
 70 }
 71 
 72 func Get() {
 73 	var addr string
 74 
 75 	fmt.Println("Enter City eg. Pune, India: ")
 76 	fmt.Scanf("%s", &addr)
 77 
 78 	// QueryEscape escapes the addr string so
 79 	// it can be safely placed inside a URL query
 80 	safeAddr := url.QueryEscape(addr)
 81 
 82 	// Geocoding API
 83 	fullUrl := fmt.Sprintf("http://maps.googleapis.com/maps/api/geocode/json?address=%s", saf\
 84 eAddr)
 85 
 86 	// Build the http request
 87 	req, err1 := http.NewRequest("GET", fullUrl, nil)
 88 	check(err1, "NewRequest:")
 89 
 90 	// For control over HTTP client headers,
 91 	// redirect policy, and other settings,
 92 	// create a Client
 93 	// A Client is an HTTP client
 94 	client := &http.Client{}
 95 
 96 	// Send the request via a client
 97 	// Do sends an HTTP request and
 98 	// returns an HTTP response
 99 	resp, err2 := client.Do(req)
100 	check(err2, "Do:")
101 
102 	// Callers should close resp.Body
103 	// when done reading from it
104 	// Defer the closing of the body
105 	defer resp.Body.Close()
106 
107 	var res Response
108 
109         // Use json.Decode or json.Encode for reading or writing streams of JSON data
110 	if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
111 		log.Println(err)
112 	}
113 
114 	// lat, lng as float64
115 	lat := res.Results[0].Geometry.Location.Lat
116 	lng := res.Results[0].Geometry.Location.Lng
117 
118 	safeLatLng := url.QueryEscape(fmt.Sprintf("%.13f,%.13f", lat, lng))
119 	url := fmt.Sprintf("https://api.forecast.io/forecast/%s/%s?units=ca", APIKey, safeLatLng)
120 
121 	resp, err := http.Get(url)
122 	check(err, "Get:")
123 	defer resp.Body.Close()
124 
125 	var f Forecast
126 
127 	if err := json.NewDecoder(resp.Body).Decode(&f); err != nil {
128 		log.Println(err)
129 	}
130 
131 	fmt.Println("The Weather at ", addr)
132 	fmt.Println("Timezone = ", f.Timezone)
133 	fmt.Println("Temp in Celsius = ", f.Currently.Temperature)
134 	fmt.Println("Summary = ", f.Currently.Summary)
135 }

The output is:

Enter City eg. Pune, India:
Pune, India
The Weather at  Pune,
Timezone =  Asia/Kolkata
Temp in Celsius =  30.59
Summary =  Mostly Cloudy

That’s it!

  1. http://golang.org/pkg/encoding/json/#Encoder.Encode
  2. http://golang.org/pkg/encoding/json/#Decoder.Decode
  3. https://developer.forecast.io/register
  4. https://developer.forecast.io/docs/v2
  5. https://github.com/kingsfleet/rest-metadata/blob/master/forecast.io/forecast.json
  6. https://github.com/kingsfleet/rest-metadata/blob/master/forecast.io/datapoint.json
  7. http://en.wikipedia.org/wiki/Query_string#URL_encoding
  8. https://developers.google.com/maps/documentation/geocoding/
  9. https://addons.mozilla.org/en-us/firefox/addon/jsonview/
  10. https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc
  11. http://golang.org/pkg/net/http/#NewRequest
  12. http://golang.org/pkg/net/http/#Client
  13. http://mholt.github.io/json-to-go/
  14. http://golang.org/pkg/net/http/#Get

19. TCP programming using Go

19.1 TCP Sockets

If you are a client you need an API that will allow you to connect to a service and then to send messages to that service and read replies back from the service.

If you are a server, you need to be able to bind to a port and listen at it. When a message comes in you need to be able to read it and write back to the client.

19.2 Package net

Usage: import "net"

Package net provides a portable interface for network I/O, including TCP/IP and UDP.

Type net.Conn1 interface is a generic stream-oriented network connection. Multiple goroutines may invoke methods on a net.Conn simultaneously.

Type net.TCPConn2 is an implementation of the net.Conn interface for TCP network connections. net.TCPConn has two major methods of interest:

  • func (c *TCPConn) Write(b []byte) (n int, err error)
  • func (c *TCPConn) Read(b []byte) (n int, err error)

A net.TCPConn is used by both a client and a server to read and write messages.

19.2.1 TCP Client

Once a client has established a TCP address for a service, it “dials” the service. If succesful, the dial returns a net.TCPConn for communication. The client and the server exchange messages on this. Typically a client writes a request to the server using the net.TCPConn, and reads a response from the net.TCPConn. This continues until either (or both) sides close the connection. A TCP connection is established by the client using the function:

func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error)

net.DialTCP connects to the remote address raddr on the network net, which must be “tcp”, “tcp4” (IPv4-only i.e. Internet Protocol version 4), or “tcp6” (IPv6-only i.e. Internet Protocol version 6). If laddr is not nil, it is used as the local address for the connection.

Note: Use “tcp” or “tcp4” or “tcp6” depending upon your computer.

A simple example can be provided by a client to a web (HTTP) server.

One of the possible messages that a client can send is the “GET” message. This queries a server for information about the server and a document on that server. The server’s response contains header as well as body, and the connection closes after the response. The request sent to query an HTTP server could be:

GET / HTTP/1.0\r\n\r\n

Program: get_info.go
 1 package main
 2 
 3 import (
 4 	"fmt"
 5 	"io/ioutil"
 6 	"log"
 7 	"net"
 8 	"os"
 9 )
10 
11 func check(e error, str string) {
12 	if e != nil {
13 		log.Fatal(str, " ", e)
14 		return
15 	}
16 }
17 
18 func main() {
19 	if len(os.Args) != 2 {
20 		fmt.Fprintf(os.Stderr, "Usage: %s host:port ", os.Args[0])
21 		os.Exit(1)
22 	}
23 	service := os.Args[1]
24 	tcpAddr, err := net.ResolveTCPAddr("tcp", service)
25 	check(err, "ResolveTCPAddr:")
26 
27 	conn, err := net.DialTCP("tcp", nil, tcpAddr)
28 	check(err, "DialTCP:")
29 
30 	// response contains header as well as body, and the connection closes after the response.
31 	_, err = conn.Write([]byte("GET / HTTP/1.0\r\n\r\n"))
32 	check(err, "Write:")
33 
34 	result, err := ioutil.ReadAll(conn)
35 	check(err, "ReadAll:")
36 
37 	fmt.Println(string(result))
38 }

To run this program, type:

go run get_info.go www.golang.com:80

The output is:

HTTP/1.0 302 Found
Cache-Control: no-store, no-cache, must-revalidate, max-age=0
Content-Type: text/html; charset=UTF-8
Location: http://www.google.co.in/?gfe_rd=cr&ei=CkNdVf-iMYT5vQS_w4H4CQ
Content-Length: 261
Date: Thu, 21 May 2015 02:29:30 GMT
Server: GFE/2.0
Alternate-Protocol: 80:quic,p=0
Pragma: no-cache
Expires: Tue, 01 Jan 1971 02:00:00 GMT

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.co.in/?gfe_rd=cr&amp;ei=CkNdVf-iMYT5vQS_w4H4CQ">here</A>.
</BODY></HTML>

In this program:

  • We use the host:port as www.golang.com:80
  • net.ResolveTCPAddr3 parses www.golang.com:80 as a TCP address of the form “host:port” and resolves a pair of domain name and port name on the network net, which must be “tcp”, “tcp4” or “tcp6”.
  • net.DialTCP4 connects to the remote address www.golang.com:80 (as a TCP address) on the network tcp (which we have used), which must be “tcp”, “tcp4”, or “tcp6”. This way we have now established a connection with the remote host.
  • conn.Write5 sends the request string.
  • Next we read and print the response. We read essentially a single response from the server. This will be terminated by end-of-file on the connection. However, it may consist of several TCP packets, so we need to keep reading till the end of file. The io/ioutil function ReadAll will look after these issues and return the complete response.

19.2.2 A Daytime server

A server registers itself on a port, and listens on that port. Then it blocks on an “accept” operation, waiting for clients to connect. When a client connects, the accept call returns, with a connection object. The daytime service is very simple and just writes the current time to the client, closes the connection, and resumes waiting for the next client.

Program: echo.go
 1 package main
 2 
 3 import (
 4         "fmt"
 5         "log"
 6 	"net"
 7 	"time"
 8 )
 9 
10 func check(e error, str string) {
11 	if e != nil {
12 		log.Fatal(str, " ", e)
13 		return
14 	}
15 }
16 
17 func main() {
18 	listener, err := net.Listen("tcp", ":6000")
19 	check(err, "Listen:")
20 
21 	for {
22 		conn, err := listener.Accept()
23 		if err != nil {
24 			log.Println(err)
25 			conn.Close()
26 			break
27 		}
28                 fmt.Println("Connected to client...")
29                 
30                 daytime := fmt.Sprintf("The Date Time is: %s", time.Now())
31 
32 		conn.Write([]byte(daytime)) // don't care about return value
33 		conn.Close()                // we're finished with this client
34 		fmt.Println("Client connection closed.")
35 	}
36 }
  • net.Listen6 listens on port 6000.
  • Accept7 implements the Accept method in the Listener interface; it waits for the next call and returns a generic Conn.
  • When a client connects to it, it will respond by sending the daytime string to it and then return to waiting for the next client.
  • The server should run forever, so that if any error occurs with a client, the server just ignores that client and carries on. A client could otherwise try to mess up the connection with the server, and bring it down.

Run the telnet client as:

telnet localhost 6000

you should see the date-time at the server location.

  1. http://golang.org/pkg/net/#Conn
  2. http://golang.org/pkg/net/#TCPConn
  3. http://golang.org/pkg/net/#ResolveTCPAddr
  4. http://golang.org/pkg/net/#DialTCP
  5. http://golang.org/pkg/net/#TCPConn.Write
  6. http://golang.org/pkg/net/#Listen
  7. http://golang.org/pkg/net/#TCPListener.Accept

20. Unit testing and Benchmarking Go programs

20.1 Testing

Usage: import "testing"

Package testing1 provides support for automated testing of Go packages. It is intended to be used in concert with the go test command.

Let us create a folder mult as follows:

$ mkdir $GOPATH/src/github.com/SatishTalim/mult

Replace SatishTalim with your GitHub id.

Next, create a file named mult.go inside that folder, containing the following Go code:

Program: mult.go
1 package mult
2 
3 func Mult2Ints(i, j int) int {
4 	return i * j
5 }

To write a new test suite, create a file whose name ends _test.go (mult_test.go in our case) that contains the TestXxx functions as shown below. Put the file in the same package as the one being tested. The file will be excluded from regular package builds but will be included when the go test command is run.

Program: mult_test.go
 1 //same package name as source file
 2 package mult 
 3 
 4 //import go package for testing related functionality
 5 import "testing" 
 6 
 7 //test function starts with "Test" and takes a pointer to type testing.T
 8 func TestMult2Ints_1(t *testing.T) { 
 9 	//try a unit test on function
10 	if Mult2Ints(3, 4) != 12 { 
11 		// log error if it did not work as expected
12 		t.Error("Mult2Ints did not work as expected.") 
13 	} else {
14 		// log some info if you want
15 		t.Log("one test passed.") 
16 	}
17 }
18 
19 //test function starts with "Test" and takes a pointer to type testing.T
20 func TestMult2Ints_2(t *testing.T) { 
21 	//Indicate that this test failed and log the string as info
22 	t.Error("this is just hardcoded as an error.") 
23 }

Please note:

  • the file name has to end with _test.go to be picked up as a set of tests by go test
  • the package name has to be the same as in the source file that has to be tested
  • you have to import the package testing
  • all test functions should start with Test to be run as a test
  • the tests will be executed in the same order that they are appear in the source
  • the test function TestXxx take a pointer to the type testing.T. You use it to record the test status and also for logging
  • the signature of the test function should always be func TestXxx ( *testing.T). You can have any combination of alphanumeric characters for the Xxx part, the only constraint that it should not begin with a small alphabet, [a-z]
  • a call to any of the following functions of testing.T within the test code Error, Errorf, FailNow, Fatal, FatalIf will indicate to go test that the test has failed

Next in the folder $GOPATH/src/github.com/SatishTalim/mult, run your tests by executing go test at the command line:

$ go test
--- FAIL: Test_Mult2Ints_2 (0.00s)
        mult_test.go:16: this is just hardcoded as an error.
FAIL
exit status 1
FAIL    github.com/SatishTalim/mult     0.103s

What happened to the first test? By default go test hides all passed results. If you want to see all the results, including the passed tests, execute it with the -v option:

$ go test -v
=== RUN Test_Mult2Ints_1
--- PASS: Test_Mult2Ints_1 (0.00s)
        mult_test.go:11: one test passed.
=== RUN Test_Mult2Ints_2
--- FAIL: Test_Mult2Ints_2 (0.00s)
        mult_test.go:16: this is just hardcoded as an error.
FAIL
exit status 1
FAIL    github.com/SatishTalim/mult     0.073s

20.2 Benchmarks

Benchmark tests allow you to check the performance of your code. It is useful when you want to test the performance between different solutions to the same problem and see which solution performs better.

Please note:

  • benchmark tests must have the signature func BenchmarkXxx ( *testing.B). You can have any combination of alphanumeric characters for the Xxx part, the only constraint it should not begin with a small alphabet, [a-z]
  • go test does not run the benchmark tests by default
  • benchmark tests are executed by the go test command when its -bench flag is provided
  • go test automatically figures out how long the test has to be run to get a reasonable benchmark result
  • to make that work, use the field testing.B.N within a loop to repeatedly run a certain function
  • no benchmark results if all the unit tests do not pass successfully. So either make sure all tests pass successfully, which of course should be the plan in any case

Add a new file shown below:

Program: mult_b_test.go
 1 //same package name as source file
 2 package mult 
 3 
 4 //import go package for testing related functionality
 5 import "testing" 
 6 
 7 //benchmark function starts with "Benchmark" and takes a pointer to type testing.B
 8 func BenchmarkTheMultIntsFunction(b *testing.B) {
 9         //use b.N for looping 
10         for i := 0; i < b.N; i++ { 
11                 Mult2Ints(4, 5)
12         }
13 }
14 
15 //benchmark function starts with "Benchmark" and takes a pointer to type testing.B
16 func BenchmarkTimeConsumingFunction(b *testing.B) {
17         //stop the performance timer temporarily while doing initialization
18         b.StopTimer() 
19 
20         //do any time consuming initialization functions here ... 
21         //database connection, reading files, network connection, etc.
22 
23         //restart timer
24         b.StartTimer() 
25         for i := 0; i < b.N; i++ {
26                 Mult2Ints(4, 5)
27         }
28 }

Run the program as follows:

$ go test -v -run="none" -bench .
PASS
Benchmark_TheMultIntsFunction   2000000000               0.65 ns/op
Benchmark_TimeConsumingFunction 2000000000               0.65 ns/op
ok      github.com/SatishTalim/mult     2.974s

In our call to , we specified the option passing go test -run the string “none” to make sure no unit tests are run prior to running the specified benchmark functions. Both these options take a regular expression to filter the tests to run. Since there is no unit test function that has none in its name, it eliminates any unit tests from running.

The benchmark function must run the target code b.N times. During benchark execution, b.N is adjusted until the benchmark function lasts long enough to be timed reliably.

The output:

Benchmark_TheMultIntsFunction 2000000000 0.65 ns/op

means that the loop ran 2000000000 times at a speed of 0.65 ns per loop.

The default minimum run time for a benchmark is 1 second. You can see how the framework still ran the test for approximately three seconds.

Let’s look at a set of benchmark functions that reveal the fastest way to convert a float value to a string. In the standard library there are two different ways to convert a float value to a string.

Let us create a folder conv as follows:

$ mkdir $GOPATH/src/github.com/SatishTalim/conv

Replace SatishTalim with your GitHub id.

Next, create a file named conv_test.go inside that folder, containing the following Go code:

Program: conv_test.go
 1 package conv
 2 
 3 import (
 4         "fmt"
 5         "testing"
 6 )        
 7 
 8 // Sample benchmarks to test which function is better for converting
 9 // an float into a string. First using the fmt.Sprintf function.
10 func BenchmarkSprintf(b *testing.B) {
11 	no := 34.56
12 
13         b.ResetTimer()
14 
15         for i := 0; i < b.N; i++ {
16 	        fmt.Sprintf("%f", no)
17 	}
18 }

Run the program as follows:

$ go test -v -run="none" -bench="BenchmarkSprintf"
testing: warning: no tests to run
PASS
BenchmarkSprintf         1000000              1365 ns/op
ok      github.com/SatishTalim/conv     3.316s

The performance of using the Sprintf function in this context is it takes 1365 nanoseconds on average per call.

The final output from running the benchmark shows ok to represent the benchmark finished properly. Then the name of the code file that was executed is displayed and finally the total time the benchmark ran. The default minimum run time for a benchmark is 1 second. You can see how the framework still ran the test for approximately more than three seconds.

Now, let us write another benchmark function in our source file conv_test.go.

Program: conv_test.go
 1 package conv
 2 
 3 import (
 4         "fmt"
 5         "strconv"
 6         "testing"
 7 )        
 8 
 9 // Sample benchmarks to test which function is better for converting
10 // an float into a string. First using the fmt.Sprintf function.
11 func BenchmarkSprintf(b *testing.B) {
12 	no := 34.56
13 
14         b.ResetTimer()
15 
16         for i := 0; i < b.N; i++ {
17 	        fmt.Sprintf("%f", no)
18 	}
19 }
20 
21 // BenchmarkFormat provides performance numbers for the
22 // strconv.FormatInt function.
23 func BenchmarkFormat(b *testing.B) {
24         no := 34.56
25 
26         b.ResetTimer()
27 
28         for i := 0; i < b.N; i++ {
29                 strconv.FormatFloat(no, 'f', 2, 64)
30         }
31 }

Run the program as follows:

$ go test -v -run="none" -bench="BenchmarkFormat"
testing: warning: no tests to run
PASS
BenchmarkFormat  1000000              1165 ns/op
ok      github.com/SatishTalim/conv     2.235s

The BenchmarkFormat function above, benchmarks the use of the function FormatFloat from the strconv package.

The call to b.ResetTimer, which is used in the two benchmark functions. This method is useful to reset the timer when initialization is required before the code can start executing the loop. To have the most accurate benchmark times you can, use this method.

The results show that the test function runs BenchmarkFormat the fastest at 1165 nanoseconds per operation.

  1. http://golang.org/pkg/testing/

21. Concurrency

Rob Pike - Concurrency is not parallelism1:

When people hear the word concurrency they often think of parallelism, a related but quite distinct concept. In programming, concurrency is the composition of independently executing processes, while parallelism is the simultaneous execution of (possibly related) computations. Concurrency is about dealing with lots of things at once. Parallelism is about doing lots of things at once.

Go allows us to write concurrent programs. It provides goroutines and importantly, the ability to communicate between them.

21.1 Goroutines

They’re called goroutines2 because the existing terms—threads, coroutines, processes, and so on—convey inaccurate connotations. A goroutine has a simple model: it is a function executing concurrently with other goroutines in the same address space. It is lightweight, costing little more than the allocation of stack space. And the stacks start small, so they are cheap, and grow by allocating (and freeing) heap storage as required.

Goroutines are multiplexed onto multiple OS threads so if one should block, such as while waiting for I/O, others continue to run. Their design hides many of the complexities of thread creation and management.

Prefix a function or method call with the go keyword to run the call in a new goroutine. When the call completes, the goroutine exits, silently.

go list.Sort() // run list.Sort concurrently; don't wait for it.

An example:

 1 package main
 2 
 3 import (
 4         "fmt"
 5         "math/rand"
 6         "time"
 7 )
 8 
 9 func f(goRtn int) {
10         for i := 0; i < 3; i++ {
11                 fmt.Println("Goroutine ", goRtn, " : Value ", i)
12                 amt := time.Duration(rand.Intn(250))
13                 time.Sleep(time.Millisecond * amt)
14         }
15 }
16 func main() {
17         for i := 0; i < 3; i++ {
18                 go f(i)
19         }
20         var input string
21         fmt.Scanln(&input)
22 }

This program consists of two goroutines. The first goroutine is implicit and is the main function itself. The second goroutine is created when we call go f(0). Normally when we invoke a function our program will execute all the statements in a function and then return to the next line following the invocation. With a goroutine we return immediately to the next line and don’t wait for the function to complete. This is why the call to the Scanln function has been included; without it the program would exit before being given the opportunity to print all the numbers.

Goroutines are lightweight and we can easily create thousands of them. Our program runs 3 goroutines.

We add some delay to the function using time.Sleep3 and rand.Intn4.

f prints out the numbers from 0 to 3, waiting between 0 and 250 ms after each one. The goroutines should now run simultaneously.

The output I get is:

Goroutine  0  : Value  0
Goroutine  1  : Value  0
Goroutine  2  : Value  0
Goroutine  0  : Value  1
Goroutine  2  : Value  1
Goroutine  1  : Value  1
Goroutine  0  : Value  2
Goroutine  2  : Value  2
Goroutine  1  : Value  2

21.2 Channels

Channels provide a way for two goroutines to communicate with one another and synchronize their execution.

Channels have several characteristics: the type of element you can send through a channel, capacity (or buffer size) and direction of communication specified by a <- operator. Thus, you can send values into channels from one goroutine and receive those values into another goroutine with the channel operator, <-.

Channels are first-class values and can be used anywhere like other values: as struct elements, function arguments, function returning values and even like a type for another channel.

1 chan <- v   // Send v to channel chan.
2 v := <-chan // Receive from chan, and
3             // assign value to v.

(The data flows in the direction of the arrow.)

Channels must be created using the built-in function make before use:

1 ch := make(chan int)

By default, sends and receives block until the other side is ready. This allows goroutines to synchronize without explicit locks or condition variables.

Let us look at a simple example:

 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6         //Create a new channel with
 7         //make(chan val-type). Channels are
 8         //typed by the values they convey
 9         messages := make(chan string)
10 
11         //Send a value into a channel using
12         //the channel <- syntax. Here we send
13         //"ping" to the messages channel we
14         //made above, from a new goroutine
15         go func() { messages <- "ping" }()
16 
17         //The <-channel syntax receives a
18         //value from the channel. Here we'll
19         //receive the "ping" message we sent
20         //above and print it out
21         msg := <-messages
22         fmt.Println(msg)
23 }

When we run the program the “ping” message is successfully passed from one goroutine to another via our channel.

By default sends and receives block until both the sender and receiver are ready. This property allowed us to wait at the end of our program for the “ping” message without having to use any other synchronization.

21.2.1 Channel direction

We can specify a direction on a channel type thus restricting it to either sending or receiving. For example if we have the following function signature:

1 func pinger(c chan<- string)

Now c can only be sent to. Attempting to receive from c will result in a compiler error. Similarly we can change signature to this:

1 func printer(c <-chan string)

A channel that doesn’t have these restrictions is known as bi-directional. A bi-directional channel can be passed to a function that takes send-only or receive-only channels, but the reverse is not true.

21.2.2 Unbuffered channel

Let’s understand this with an example:

 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6         fmt .Println("From main()")
 7 
 8         // Create a channel to synchronize goroutines
 9         done := make(chan bool)
10 
11         // Execute fmt.Println in goroutine
12         go func() {
13                 sum := 0
14                 for i := 0; i < 10000; i++ {
15                         sum += i
16                 }
17                 fmt.Println("From goroutine - done.")
18 
19                 // Tell the main function everything is done.
20                 // This channel is visible inside this goroutine because
21                 // it is executed in the same address space.
22                 done <- true
23         }()
24 
25         <-done // Read operation: Wait for the goroutine to finish
26 }

Observe the output. The line “From main()” is blocked i.e. it is not printed until the goroutine has writen data to the channel. Thus the output you see is:

From main()
From goroutine - done.

both being printed at the same time.

Note: If the channel is unbuffered, the sender blocks until the receiver has received the value.

In the above program, the done channel has no buffer (as we did not specify its capacity). All operations on unbuffered channels block the execution until both sender and receiver are ready to communicate. That’s why unbuffered channels are also called synchronous. In our case the reading operation <-done in the main function will block its execution until the goroutine will write data to the channel. Thus the program ends only after the reading operation (<-done) succeeds.

  1. http://blog.golang.org/concurrency-is-not-parallelism
  2. http://golang.org/doc/effective_go.html#goroutines
  3. http://golang.org/pkg/time/#Sleep
  4. https://golang.org/pkg/math/rand/#Intn

22. Additional Exercises

1 package main
2 
3 import "fmt"
4 
5 func main() {  
6         x := "text"
7         fmt.Println(x[0]) //print 116
8 }
 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {  
 6     data := []int{1,2,3}
 7     i := 0
 8     ++i //error
 9     fmt.Println(data[i++]) //error
10 }
 1 package main
 2 
 3 import (  
 4         "fmt"
 5         "log"
 6         "net/http"
 7         "io/ioutil"
 8 )
 9 
10 func check(e error, str string) {
11 	if e != nil {
12 		log.Fatal(str, " ", e)
13 		return
14 	}
15 }
16 
17 func main() {  
18         resp, err := http.Get("https://api.ipify.org?format=json")
19         defer resp.Body.Close()
20         check(err, "http.Get:")
21 
22         body, err := ioutil.ReadAll(resp.Body)
23         check(err, "ReadAll:")
24 
25         fmt.Println(string(body))
26 }

22.1 Solutions

Exercise A1 Solution1. Another solution for A12.

Exercise A2 Reason: The index operator on a string returns a byte value, not a character (like it’s done in other languages). For more details, read the topic on conversions3.

Exercise A3 Reason: Many languages have increment and decrement operators. Unlike other languages, Go doesn’t support the prefix version of the operations. You also can’t use these two operators in expressions.

Exercise A4 Solution:

Exercise A5 Reason: When you make requests using the standard http library you get a http response variable. If you don’t read the response body you still need to close it. You must do it for empty responses too. It’s very easy to forget especially. Some new Go developers do try to close the response body, but they do it in the wrong place as was done in the given program. The most common why to close the response body is by using a defer call after the http response error check.

Most of the time when your http request fails the resp variable will be nil and the err variable will be non-nil. However, when you get a redirection failure both variables will be non-nil.

A better way is:

1         resp, err := http.Get("https://api.ipify.org?format=json")
2         defer func() {if resp != nil {resp.Body.Close()}}()
3         check(err, "http.Get:")

Exercise A6 Solution.

  1. http://play.golang.org/p/p3fyS28NKy
  2. http://play.golang.org/p/iZm6VBVa8S
  3. http://golang.org/ref/spec#Conversions

23. Additional Reading

23.1 Testable Examples in Go

Godoc examples are snippets of Go code that are displayed as package documentation and that are verified by running them as tests. They can also be run by a user visiting the godoc web page for the package and clicking the associated “Run” button.

Read 11 Read 22

  1. https://blog.golang.org/examples
  2. https://godoc.org/github.com/natefinch/godocgo

Appendix A

Downloading Go

Visit the Go project’s downloads page1 and select the binary distribution that matches your operating system and processor architecture.

Install the Go tools

Read through the installation guide2 for Linux, Mac OS X, FreeBSD and Windows.

The Go binary distributions assume they will be installed in /usr/local/go (or c:\Go under Windows), but it is possible to install them in a different location. If you do this, you will need to set the GOROOT environment variable to that directory when using the Go tools.

For example, if you installed Go to your home directory you should add the following commands to $HOME/.profile:

export GOROOT=$HOME/go
export PATH=$PATH:$GOROOT/bin

Under Windows, you may set environment variables through the “Environment Variables” button on the “Advanced” tab of the “System” control panel. Some versions of Windows provide this control panel through the “Advanced System Settings” option inside the “System” control panel.

The Go-environment works with a small number of OS environment variables. They are not required for building the Go-environment, but by setting them and thus overriding the defaults the Go compilation environment can be customized. I have set the following:

Name Value
GOROOT C:\go
GOOS windows
GOARCH 386

Environment Variables

On Windows:

In the same dialog-window: Edit the PATH-variable as follows:

C:\go\bin; ...rest of PATH...

Test your installation

Check that Go is installed correctly by building a simple program, as follows.

Create a file named hello_world.go in some folder (for now) and put the following program in it:

1 package main
2 
3 import "fmt"
4 
5 func main() {
6         fmt.Println("Hello, world.")
7 }

Then from the folder where you have saved the file hello_world.go run it with the go tool:

$ go run hello_world.go
Hello, world.

If you see the “Hello, world.” message then your Go installation is working.

Go Code Organization

The go tool3 is the standard way to fetch, build, and install Go packages and commands. The go tool requires you to organize your code in a specific way.

Workspaces

Go code must be kept inside a workspace. A workspace is a directory hierarchy with three directories at its root:

  • src contains Go source files organized into packages (one package per directory),
  • pkg contains package objects, and
  • bin contains executable commands.

The go tool builds source packages and installs the resulting binaries to the pkg and bin directories.

The src subdirectory typically contains version control repositories (such as for Git) that track the development of one or more source packages.

The GOPATH environment variable

The GOPATH environment variable specifies the location of your workspace.

To get started, create a workspace directory and set GOPATH accordingly. Your workspace can be located wherever you like. Note that this must not be the same path as your Go installation.

On my Windows computer, I have set GOPATH=C:\go_projects\go. Next I update my system environment variable PATH to include my workspace bin subdirectory i.e. PATH=%PATH%;%GOPATH%\bin;

We need to do the same on *nix or Mac as well.

mkdir $HOME/go_projects/go
export GOPATH=$HOME/go_projects/go
export PATH=$PATH:$GOPATH/bin
My workspace folder structure
C:\go_projects
\---go
    +---bin
    +---pkg
    \---src

Package paths

The packages from the standard library are given short paths such as fmt and net/http. For your own packages, you must choose a base path that is unlikely to collide with future additions to the standard library or other external libraries. If you have a GitHub account at github.com/user, that should be your base path. We will use github.com/user as our base path. Create a directory inside your workspace in which to keep the source code. I have created the folder C:\go_projects\go\src\github.com\SatishTalim.

Editing a Go program

Go programs are written as plain text Unicode using the UTF-8 encoding. All of Go’s keywords and operators use ASCII characters; however, Go identifiers can start with any Unicode letter followed by any Unicode letters or digits, so Go programmers can freely use their native language.

A Go program

To compile and run a simple program, first choose a package path and create a corresponding package directory inside your workspace:

$ mkdir $GOPATH/src/github.com/SatishTalim/hello

Next, create a file named hello.go inside that directory, containing the following Go code:

1 package main
2 
3 import "fmt"
4 
5 func main() {
6         fmt.Printf("Hello, world.\n")
7 }

Now you can build and install that program with the go tool:

$ cd $GOPATH/src/github.com/SatishTalim/hello
$ go install

The go tool will only print output when an error occurs, so if these commands produce no output they have executed successfully.

The above command i.e. go install4 compiles, builds the hello executable binary and then installs that binary to the workspace’s bin directory as hello (or, under Windows, hello.exe).

You can now run the program by typing:

$ hello
Hello, world.
  1. https://golang.org/dl/
  2. https://golang.org/doc/install
  3. http://golang.org/cmd/go/
  4. https://golang.org/cmd/go/#hdr-Compile_and_install_packages_and_dependencies

Appendix B - Project: redditnews for Baby Gophers

baby-gopher
baby-gopher

I am keen to be abreast with what’s happening in the Golang world. To that end, we will write a command-line program (redditnews.go) that fetches and displays the latest headlines from the golang page on Reddit.

The program will:

  • make an HTTP request to the Reddit API.
  • decode the JSON response into a Go data structure, and
  • display each link’s author, score, URL and title.

We will then be building a bare-bones News Reader package (redditnews) that gives us the latest news and headlines from the Golang Sub-Reddit, using Reddit’s API.

Once the project is ready, we will use GMail to send an email which will contain the information fetched by the package redditnews.

Use GitHub

One of the best places to share your code with friends, co-workers, classmates, and complete strangers is GitHub1.

Create an account

On the main screen that shows up, enter your username, your email and create a password. Next, click on Sign up for GitHub. On the next screen, The ‘Free’ plan is automatically chosen for you. Just click on the Finish sign up button. You will receive an email asking you to ‘Confirm your email’. Please do that.

Set up Git

Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.

If you are new to Git, then learn Git in 15 minutes2.

Next, Set Up Git3 on your computer as per the guide.

Complete Appendix A

I am assuming that you have completed Appendix A.

redditnews.go (First Iteration)

This is the first draft of my program.

In your browser, open the site http://reddit.com/r/golang.json4 the browser output is a huge blob of JSON that we receive from the Golang Subreddit. This may be difficult to look at in the browser, unless you have the JSONView plugin installed. These extensions are available for Firefox5 and Chrome. With the extension installed, here’s a partial view of the JSON:

JSON
JSON

Now let’s write the first draft of our program.

Make a new folder and cd to it as follows:

$ mkdir $GOPATH/src/github.com/SatishTalim/redditnews
$ cd $GOPATH/src/github.com/SatishTalim/redditnews

In this folder, create a file named redditnews.go, open it in your favorite editor, and add the following lines:

Program redditnews.go
package main

import (
	"io"
	"log"
	"net/http"
	"os"
)

func main() {
	resp, err := http.Get("http://reddit.com/r/golang.json")
	if err != nil {
		log.Fatal(err)
	}

	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		log.Fatal(resp.Status)
	}

	_, err = io.Copy(os.Stdout, resp.Body)
	if err != nil {
		log.Fatal(err)
	}
}
  • Like all Go programs that need to be executed, our program has a package main.
  • Package io6 provides basic interfaces to I/O primitives.
  • On an error we use log7. Package log implements a simple logging package. It defines a type, Logger, with methods for formatting output. It also has a predefined ‘standard’ Logger accessible through helper functions Print[f|ln], Fatal[f|ln], and Panic[f|ln], which are easier to use than creating a Logger manually. That logger writes to standard error and prints the date and time of each logged message.
  • The log.Fatal function prints the error message and exits the program.
  • For web related http functionality, we import the package net/http8. Any functions within that we refer as http.function_name.
  • Package os9 provides a platform-independent interface to operating system functionality.
  • In our main() function, we are setting a variable resp and doing a GET request to the Reddit API on our chosen Subreddit.
  • The func Get(url string) (resp *Response, err error) issues a GET to the specified URL. When err is nil, resp always contains a non-nil resp.Body. Caller should close resp.Body when done reading from it. The resp is of type Response10.
  • We use the defer function to clean up after the HTTP request, and this call will only be executed after the function returns.
  • In our Error Handling, check that the HTTP server returns a “200 OK” response. If not, bail, printing the HTTP status message (“500 Internal Server Error”, for example).
  • The package net/http defines many constants11.
  • _ is a blank identifier which can be used when we don’t care about a particular return value.
  • Finally, we copy the resp.Body (filled with the JSON received from the Reddit API) to the os.Stdout. The resp.Body type implements io.Reader and os.Stdout implements io.Writer.

Now you can run the program with the go tool:

$ cd $GOPATH/src/github.com/SatishTalim/redditnews
$ go run redditnews.go

When you run the program we are outputting (through os.Stdout) a huge blob of JSON that we received from the Golang Subreddit. Although we can actually see the Articles inside there, this is no good to us. We want to receive the Article’s Title, Author’s name, a Link to the Article, and we want to assess the value of the article, based on the Reddit link Score the Article has received.

  1. https://github.com/
  2. https://try.github.io/levels/1/challenges/1
  3. https://help.github.com/articles/set-up-git
  4. https://news.ycombinator.com/item?id=9315144
  5. https://addons.mozilla.org/en-us/firefox/addon/jsonview/
  6. http://golang.org/pkg/io/
  7. http://golang.org/pkg/log/
  8. http://golang.org/pkg/net/http/
  9. http://golang.org/pkg/os/
  10. http://golang.org/pkg/net/http/#Response
  11. http://golang.org/pkg/net/http/#pkg-constants

Appendix C - Build, deploy webapps to cloud

Complete Appendix A

I am assuming that you have completed Appendix A.

A basic Go web app

Our objective here is to build a web app in Go. In the following program, we shall start a simple service on our local machine. We will have the program running on some port number. When you access the local machine at http://localhost:port_no (which is the same as http://127.0.0.1:port_no), it will print a text message on the screen.

Make a new folder and cd to it as follows:

1 $ mkdir $GOPATH/src/github.com/SatishTalim/webapp
2 $ cd $GOPATH/src/github.com/SatishTalim/webapp

Note: Replace SatishTalim with your GitHub name.

In this folder, create a file named webapp.go, open it in your favorite editor, and add the following lines:

Program webapp.go
 1 package main
 2 
 3 import (
 4 	"fmt"
 5 	"log"
 6 	"net/http"
 7 	"os"
 8 )
 9 
10 func main() {
11 	http.HandleFunc("/", handler)
12 
13 	err := http.ListenAndServe(GetPort(), nil)
14 	if err != nil {
15 		log.Fatal("ListenAndServe: ", err)
16 	}
17 }
18 
19 func handler(w http.ResponseWriter, r *http.Request) {
20 	fmt.Fprintf(w, "Hello. This is our first Go web program!")
21 }
22 
23 // Get the Port from the environment so we can run on Heroku
24 func GetPort() string {
25 	var port = os.Getenv("PORT")
26 	// Set a default port if there is nothing in the environment
27 	if port == "" {
28 		port = "4747"
29 		fmt.Println("INFO: No PORT environment variable detected, defaulting to " + port)
30 	}
31 	return ":" + port
32 }
  • like all Go programs that need to be executed, our program has a package main.
  • we import the fmt1 and net/http2 packages from the Go standard library.
  • to work with some printing functions, we import the package fmt.
  • package os3 provides a platform-independent interface to operating system functionality.
  • for web related http functionality, we import the package http4. Any functions within that we refer as http.function_name.
  • the first thing we need to do is tell our server what to do when someone comes to our homepage. So, we need to have a request handler at root (“/”). Within the main program, we redirect any incoming requests to the handler function. We do this by calling http.HandleFunc and passing it two parameters - the first one is a part of the incoming url, and the second is the method capable of handling it.
  • it then calls http.ListenAndServe, specifying that it should listen on port returned by our local function GetPort which internally calls Getenv (retrieves the value of the environment variable named by the key. It returns the value, which will be empty if the variable is not present) on any interface. (Don’t worry about its second parameter, nil, for now.) This function will block until the program is terminated.
  • on an error we use log5. Package log implements a simple logging package. It defines a type, Logger, with methods for formatting output. It also has a predefined ‘standard’ Logger accessible through helper functions Print[f|ln], Fatal[f|ln], and Panic[f|ln], which are easier to use than creating a Logger manually. That logger writes to standard error and prints the date and time of each logged message.
  • the function handler is of the type http.HandlerFunc. It takes an http.ResponseWriter and an http.Request as its arguments.
  • when a user connects, the program responds with a text that is sent back to the browser. The http.ResponseWriter value assembles the HTTP server’s response; by writing to it, we send data to the HTTP client.
  • an http.Request is a data structure that represents the client HTTP request.
  • all the parameters of a request can be received via the parameter http.Request in the handler. You can get the URL, the input values and other details.

Now you can build and install that program with the go tool:

$ cd $GOPATH/src/github.com/SatishTalim/webapp
$ go install

You can now run the program by typing:

$ webapp
listening...
INFO: No PORT environment variable detected, defaulting to 4747

If you run this program and access the URL: http://localhost:47476 the program would present a page containing:

Hello. This is our first Go web program!

Great, it worked!

Static Sites with Go

A web application7 or web app is any application software that runs in a web browser or is created in a browser-supported programming language (such as the combination of JavaScript, HTML and CSS) and relies on a common web browser to render the application.

HTTP means HyperText Transfer Protocol. HTTP uses a simple conversation pattern: the client connects to the server, initiates the dialog by asking the server for something, the server then tries to provide the client with an answer (back). The basic principle of HTTP, and the Web in general, is that every resource (such as a web page) available on the Web has a distinct Uniform Resource Locator (URL), and that web clients can use HTTP verbs such as GET, POST, PUT, and DELETE to retrieve or otherwise manipulate those resources.

Our objective is to build a web app in Go to display a static site, which we call “Dosa Diner”.

Dosa is a fermented crepe or pancake made from rice batter and black lentils. This staple dish is widely popular in all southern Indian states Karnataka, Andhra Pradesh, Tamil Nadu and Kerala, as well as being popular in other countries like Sri Lanka, Malaysia and Singapore.

To build this static site, as mentioned before, you should have an understanding of basic web technologies (HTTP, HTML). In the following program, we shall start a simple service on our local machine. We will have the program running on port 3000. When you access the local machine at http://localhost:47478 (which is the same as http://127.0.0.1:47479), it will display a static site on the screen. Start by creating the folders to hold the project:

DosaSite folder structure
c:\go_projects
\---go
    \---src
        \---github.com
            \---SatishTalim
                \---dosasite
                    |   dosasite.go
                    |   
                    \---public
                        |   index.html
                        |   
                        +---images
                        |       dosa.jpg
                        |       
                        \---stylesheets
                                dosasite.css

We will write our Go code in the file dosasite.go and some sample HTML and CSS files in a public folder.

File index.html
 1 <!DOCTYPE html>
 2 <html>
 3 
 4   <head>
 5     <title>Dosa Diner</title>
 6     <meta charset="utf-8">
 7     <link rel="stylesheet" href="stylesheets/dosasite.css">
 8   </head>
 9 
10   <body>
11   <h1><img src="images/dosa.jpg" alt="Dosa Diner" />Dosa Diner</h1>
12 
13   <h2>The Restaurant</h2>
14   <p>The Dosa Diner offers casual lunch and dinner fare in a hip atmosphere.
15      The menu changes regularly to highlight the freshest ingredients.</p>
16 
17   <h2>Catering Services</h2>
18   <p>You have fun... we'll do the cooking. Dosa Diner Catering can handle events
19      from snacks for bridge club to elegant corporate fundraisers.</p>
20 
21   <h2>Location and Hours</h2>
22   <p>Deccan Corner in Pune, India;
23   Monday through Thursday 11am to 9pm, Friday and Saturday, 11am to midnight.</p>
24   </body>
25 
26 </html>
File dosasite.css
 1 body {
 2   background-color: #C2A7F2;
 3   font-family: sans-serif;
 4 }
 5 h1 {
 6   color: #2A1959;
 7   border-bottom: 2px solid #2A1959;
 8 }
 9 h2 {
10   color: #474B94;
11   font-size: 1.2em;
12 }
13 h2, p {
14   margin-left: 120px;
15 }

Once the above files are created, the code we need to get up and running is quite compact:

Program dosasite.go
 1 package main
 2 
 3 import (
 4         "fmt"
 5         "log"
 6         "net/http"
 7         "os"
 8 )
 9 
10 func main() {
11         fs := http.FileServer(http.Dir("public"))
12         http.Handle("/", fs)
13 
14         fmt.Println("Listening...")
15         err := http.ListenAndServe(GetPort(), nil)
16         if err != nil {
17                 log.Fatal("ListenAndServe: ", err)
18                 return
19         }
20 }
21 
22 // Get the Port from the environment so we can run on Heroku (more of this later)
23 func GetPort() string {
24         var port = os.Getenv("PORT")
25 	// Set a default port if there is nothing in the environment
26 	if port == "" {
27 		port = "4747"
28 		fmt.Println("INFO: No PORT environment variable detected, defaulting to " + port)
29 	}
30 	return ":" + port
31 }
  • like all Go programs that need to be executed, our program has a package main.
  • we import the fmt10 and net/http11 packages from the Go standard library.
  • to work with some printing functions, we import the package fmt.
  • for web related http functionality, we import the package http. Any functions within that we refer as http.function_name.
  • we use the FileServer12 function to create a handler that responds to HTTP requests with the contents of a given FileSystem13.
  • we use the operating system’s file system implementation by http.Dir
  • we’ve used the public folder relative to our application, but you could use any other folder on your system (or indeed anything that implements the FileSystem interface).
  • we use the Handle14 function to register it as the handler for all requests, and launch the server listening on port 4747.

Now you can run program with the go tool:

$ cd $GOPATH/src/github.com/SatishTalim/dosasite
$ go run dosasite.go

Now open http://localhost:4747/index.html15 in your browser. You should see the HTML page we have made.

DosaSite
DosaSite

Deploying Go Web Apps to Heroku

There are plenty of definitions for “cloud computing” online, and for the most part, they generally point to the same thing: taking applications and running them on infrastructure other than your own. Companies or individuals who offload or effectively “outsource” their hardware and/or applications are running those apps “in the cloud.”

Cloud Computing Service Levels

In the figure below, you can see how the analyst firm Gartner segregates cloud computing into three distinct classes of service.

Cloud Computing Service Levels
Cloud Computing Service Levels

SaaS

Let’s start at the highest level: software applications that are only available online fall into the “Software-as-a-Service” category, also known as “SaaS”. The simplest example to understand is e-mail. For personal e-mail, people typically select from a variety of free web-based e-mail servers such as Google’s Gmail, Yahoo!Mail, or Microsoft’s Hotmail, rather than setting up all of the above through their provider. Not only is it “free” (supported through advertising), but users are freed from any additional server maintenance. Because these applications run (and store their data online), users no longer need to worry about managing, saving, and backing up their files. Of course, now it becomes Google’s responsibility to ensure that your data is safe and secure. Other examples of SaaS include Salesforce, IBM’s NetSuite, and online games.

IaaS

On the opposite end of the spectrum, we have “Infrastructure-as-a-Service,” or “IaaS,” where you outsource the hardware. In such cases, it’s not just the computing power that you rent; it also includes power, cooling, and networking. Furthermore, it’s more than likely that you’ll need storage as well. Generally IaaS is this combination of compute and cloud storage.

When you choose to run your applications at this cloud service level, you’re responsible for everything on the stack that is required to operate above it. By this, we mean necessities such as the operating system followed by additional (yet optional services) like database servers, web servers, load-balancing, monitoring, reporting, logging, middleware, etc. Furthermore, you’re responsible for all hardware and software upgrades, patches, security fixes, and licensing, any of which can affect your application’s software stack in a major way.

PaaS

In the middle, we have “Platform-as-a-Service,” or “PaaS.” At this service level, the vendor takes care of the underlying infrastructure for you, giving you only a platform with which to (build and) host your application(s). Gone are the hardware concerns of IaaS, yet with PaaS, you control the application — it’s your code — unlike as the SaaS level where you’re dependent on the cloud software vendor. The only thing you have to worry about is your application itself.

Systems like Google App Engine, Salesforce’s Heroku and force.com, Microsoft Azure, and VMwares Cloud Foundry, all fall under the PaaS umbrella.

A number of Platform-as-a-Service (PaaS) providers16 allow you to use Go applications on their clouds.

Heroku17 is a new approach to deploying web applications18. Forget about servers; the fundamental unit is the app. Develop locally on your machine just like you always do. When you’re ready to deploy, use the Heroku client gem to create your application in their cloud, then deploy with a single git push. Heroku has full support for Go applications.

We shall soon see how we can deploy an app to Heroku.

Program webapp_h.go

Inside the folder $GOPATH/src/github.com/SatishTalim create the folder webapp_h.

Next inside the webapp_h folder, create a file named webapp_h.go, and give it the following contents:

Program webapp_h.go
 1 package main
 2 
 3 import (
 4 	"fmt"
 5 	"log"
 6 	"net/http"
 7 	"os"
 8 )
 9 
10 func main() {
11 	http.HandleFunc("/", handler)
12 	fmt.Println("listening...")
13 	err := http.ListenAndServe(GetPort(), nil)
14 	if err != nil {
15 		log.Fatal("ListenAndServe: ", err)
16 	}
17 }
18 
19 func handler(w http.ResponseWriter, r *http.Request) {
20 	fmt.Fprintf(w, "Hello. This is our first Go web app on Heroku!")
21 }
22 
23 // Get the Port from the environment so we can run on Heroku
24 func GetPort() string {
25 	var port = os.Getenv("PORT")
26 	// Set a default port if there is nothing in the environment
27 	if port == "" {
28 		port = "4747"
29 		fmt.Println("INFO: No PORT environment variable detected, defaulting to " + port)
30 	}
31 	return ":" + port
32 }

This Go package responds to any request by sending a response containing the message: Hello. This is our first Go web app for Heroku!

Create an account on Heroku

Please ensure that you are connected to the internet and then create an account on Heroku (obviously do this only once). If you don’t have one, then signup19. It’s free and instant. A free account can have upto 5 apps without registering your credit card.

Note: I just read on reddit that Heroku is moving away from free dynos20, which is sad.

Install the Heroku Toolbelt

The Heroku Toolbelt21 ensures that you have access to the Heroku command-line client, Foreman which is used to run applications locally, and the Git revision control system that is used to deploy sites to Heroku.

Once installed, you’ll have access to the heroku command from your command window. Log in using the email address and password you used when creating your Heroku account:

$ cd $GOPATH/src/github.com/SatishTalim/webapp_h
$ heroku login
Enter your Heroku credentials.
Email: golangchallenge@gmail.com
Password:
Could not find an existing public key.
Would you like to generate one? [Yn]
Generating new SSH public key.
Uploading ssh public key /Users/satish/.ssh/id_rsa.pub

Create a Procfile

Create a Procfile to tell Heroku what command to run for the web process in our app. The Procfile should be created in the folder $GOPATH/src/github.com/SatishTalim/webapp_h and contains:

web: webapp_h

Use Git

In order to deploy to Heroku we’ll need the app stored in Git. In the same folder i.e. $GOPATH/src/github.com/SatishTalim/webapp_h type:

$ git init
$ git add -A .
$ git commit -m "code"

Install Godep

The recommended way to manage Go package dependencies on Heroku is with Godep22, which helps build applications reproducibly by fixing their dependencies.

Before installing Godep ensure that you have Mercurial23 installed (check that you have an hg command) and have set the path environment variable for mercurial for eg. c:\Mercurial.

Now let us install Godep:

$ go get github.com/kr/godep

Now save your dependencies:

$ godep save

This will save a list of dependencies to the file Godeps/Godeps.json, and copy their source code into Godeps/_workspace.

Add these new files to git:

$ git add -A .
$ git commit -m "dependencies"

Now we’re ready to ship this to Heroku.

Heroku deploy

Create a new Heroku app, telling it to use the Go Heroku Buildpack24 to build your Go code:

$ heroku create -b https://github.com/kr/heroku-buildpack-go.git
Creating tranquil-bastion-1774... done, stack is cedar
BUILDPACK_URL=https://github.com/kr/heroku-buildpack-go.git
http://tranquil-bastion-1774.herokuapp.com/ | git@heroku.com:tranquil-bastion-1774.git
Git remote heroku added

Push the code to Heroku:

$ git push heroku master
Initializing repository, done.
Counting objects: 11, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (8/8), done.
Writing objects: 100% (11/11), 1.29 KiB | 0 bytes/s, done.
Total 11 (delta 0), reused 0 (delta 0)

-----> Fetching custom git buildpack... done
-----> Go app detected
-----> Installing go1.2... done
-----> Running: godep go install -tags heroku ./...
-----> Discovering process types
       Procfile declares types -> web

-----> Compressing... done, 1.7MB
-----> Launching... done, v4
       http://pumpkin-cupcake-1256.herokuapp.com deployed to Heroku

To git@heroku.com:pumpkin-cupcake-1256.git
 * [new branch]      master -> master

Your app should be up and running. Visit it with:

$ heroku open
Opening pumpkin-cupcake-1256... done

That’s it - you now have a running Go app on Heroku!

Here’s the URL again: http://pumpkin-cupcake-1256.herokuapp.com/25.

A brief note on Heroku

Troubleshooting

A number of bugs can potentially be encountered in the process of deploying a Go application to Heroku. Many times, a bug can be traced to a misunderstanding of Heroku’s architecture and how it works.

Heroku’s Architecture

Overall, Heroku applications are expected to follow the “process model”26 architecture. The process model allows applications, and web applications in particular, to be easily scaled out and managed with little administrative overhead. In exchange, the architecture requires applications to conform to certain rules and restrictions.

There are two fundamental parts to a Heroku application: Dynos, which follow the proccess model; and Add-ons, which are provided through third-party integrations.

Dynos

The main unit of a Heroku application is the Dyno.

Dynos are ephemeral servers which run a single process. Each process started by a dyno must be assigned a “process type”. A dyno’s type is defined by the starting process type.

Even though a dyno can only start a single process, once started that process may spawn additional processes within the dyno within limits27.

Keep in mind, dynos do not retain data. Data does not persist between Dyno restarts and there are no shared volumes between dynos. Practically speaking, you cannot retain any data on a dyno. Add-ons28 should be used for persistence and are explained below.

There are three types29 of Dynos tailored for different workloads: web dynos, worker dynos, and one-off dynos.

Only web dynos receive HTTP traffic via the Heroku router. Heroku assigns a single $PORT environment variable to all dynos running a web process type. All inbound HTTP traffic to a web process goes through the single assigned $PORT variable. The Heroku router attaches headers30 to HTTP requests to describe the original request as received by Heroku.

Web Dynos also have the following restrictions not discussed above: - They allow 50 active requests per web dyno with a 50 request queue. - They must connect to the Heroku provided $PORT environment variable within 60 seconds31 or the dyno will automatically be shut down.

Add-ons

Persistence and other functionality needed by applications which cannot be provided by Dynos are available through Add-ons32. Many add-ons are integrated with Dynos through environment variables.

Slugs

In addition to the process described above, Go applications can also be cross-compiled into a binary and deployed to Heroku through the use of a custom slug. Slugs are containers (similar to Docker images) which hold everything needed to run a program on Heroku’s infrastructure. To deploy a Go application this way, a slug needs to be created, published, and released on Heroku. Heroku has published an article specifically about deploying Go slugs33.

White House
White House

The address used in the exercise above is that of a landmark, historic home and office of the United States president.

Exercise 18 Solution:

Exercise 19 Solution:

License

This work is licensed under the Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a copy of this license, visit here36.

All example code used in this book is hereby put in the public domain.

©Satish Talim - 2015

  1. http://golang.org/pkg/fmt/
  2. http://golang.org/pkg/net/http/
  3. http://golang.org/pkg/os/
  4. http://golang.org/pkg/net/http/
  5. http://golang.org/pkg/log/
  6. http://localhost:4747
  7. http://en.wikipedia.org/wiki/Web_application
  8. http://localhost:4747
  9. http://127.0.0.1:4747
  10. http://golang.org/pkg/fmt/
  11. http://golang.org/pkg/net/http/
  12. http://golang.org/pkg/net/http/#FileServer
  13. http://golang.org/pkg/net/http/#FileSystem
  14. http://golang.org/pkg/net/http/#Handle
  15. http://localhost:4747/index.html
  16. https://code.google.com/p/go-wiki/wiki/ProviderIntegration
  17. http://heroku.com/
  18. http://mmcgrana.github.io/2012/09/getting-started-with-go-on-heroku.html
  19. http://heroku.com/signup
  20. https://news.ycombinator.com/item?id=9315144
  21. https://toolbelt.heroku.com
  22. https://github.com/kr/godep
  23. http://mercurial.selenic.com/downloads/
  24. https://github.com/kr/heroku-buildpack-go
  25. http://pumpkin-cupcake-1256.herokuapp.com/
  26. https://devcenter.heroku.com/articles/process-model
  27. https://devcenter.heroku.com/articles/dynos#process-thread-limits
  28. https://addons.heroku.com/
  29. https://devcenter.heroku.com/articles/dynos#types-of-dynos
  30. https://devcenter.heroku.com/articles/http-routing#heroku-headers
  31. https://devcenter.heroku.com/articles/dynos#web-dynos
  32. https://addons.heroku.com/
  33. https://devcenter.heroku.com/articles/platform-api-deploying-slugs#go
  34. https://developers.google.com/maps/documentation/geocoding/
  35. https://developers.google.com/maps/documentation/streetview/index
  36. http://creativecommons.org/licenses/by-nc-sa/3.0/