The Go programming language was developed at Google by Robert Griesemer and UNIX luminaries Rob Pike and Ken Thompson. It is an open source, high-level, compiled, highly efficient, strongly statically typed programming language. Go supports both procedural and object-oriented programming, though its object-orientation is quite different from other object-oriented programming languages like C++, Java, etc.
Some of the features of Go that we will look at are: object-orientation without class, inheritance and overloading, duck typing, closure, concurrency; built-in support for slices, maps and strings; and fast compilation, among others. Lets install Go first. I will describe the installation steps on Ubuntu 15.04, though it can be installed on any distribution of your choice. Go can be installed either from the binary as follows:
$ sudo apt-get install golang
or from the Go source code. I will cover the second method of installation, step-by-step.
Step 1: Install the prerequisites package. We need Git to complete the installation.
$ sudo apt-get install git
Step 2: Download the Go set-up tree. The Go source code is written in Go itself; so to create the bootstrap, we need a workable Go set-up. Download the Go 1.4 set-up tree and configure it as follows:
$ wget https://storage.googleapis.com/golang/go1.4.linux-386.tar.gz $ mkdir $HOME/bootstrap $ tar -C $HOME/bootstrap -xzf go1.4.linux-386.tar.gz $ export GOROOT_BOOTSTRAP=$HOME/bootstrap/go
Step 3: Get the Go source and compile it as follows:
$ mkdir $HOME/source $ cd $HOME/source $ git clone https://go.googlesource.com/go $ cd go $ git checkout go1.5 $ cd src $ ./all.bash
This takes some time. If everything goes right, you should get the message ALL TESTS PASSED’ along with some other responses. Now, add the Go bin directory to your PATH environment variable, as follows:
$ export PATH=$PATH:$HOME/source/go/bin'
Step 4: Check for the Go installation, by using the following command:
$ go version go version go1.5 linux/386
Your actual output may vary, depending on your computer architecture.
Step 5: Create the GOPATH environment variable, as follows:
$ mkdir $HOME/workspace $ export GOPATH=$HOME/workspace
Step 6: Install the Go tool godoc, by issuing the following code:
$ go get golang.org/x/tools/cmd/godoc
Step 7: Check the godoc installation by issuing the following command:
$ godoc usage: godoc package [name ]
This displays godoc help. Here, its truncated after the first line.
Step 8: Set the required environment variables for Go development, as follows:
$ export PATH=$PATH:$GOPATH/bin $ export GOBIN=$GOPATH/bin
Step 9: Add all the export commands executed so far in the $HOME/.bashrc file to make them permanent. Now, log out and log in to get all the environment variables updated.
Our first Go program
Lets write our first Go program, a simple implementation of a stack data structure of integers, i.e., a last in, first out list of integers. In this version, I have intentionally avoided all the bells and whistles of the Go language in order to help readers first understand the basics. We will update our program gradually to learn different concepts of the Go language.
Go code is organised in packages. A package can span over multiple .go files. We have two files in this example the stack package in $GOPATH/src/gostack/stack/stack.go, and the main package, which contains the main() function, the entry point of our program in $GOPATH/src/gostack/gostack.go. Lets go through our stack.go code first.
$GOPATH/src/gostack/stack/stack.go // The code in this file belongs to the stack package package stack // Import the required packages, here only error import fmt // C reate a Stack type, which is a slice of integers type Stack []int // Push function to push item onto the stack given as argument func Push(stack *Stack, item int) { *stack=append(*stack,item) } // Pop function to pop item from the stack given as argument func Pop(stack *Stack,item *int) bool { if len(*stack)==0 { // len() returns the no of elements in a slice fmt.Println(Pop:: The stack is empty) return false } // remove the last element from the slice in item *item=(*stack)[len(*stack)-1] // creates a new slice by taking the ele from first to second last *stack=(*stack)[:len(*stack)-1] return true } // Show function to display the content of the stack func Show(stack Stack) { if len(stack)!=0 { fmt.Printf([ ) for _,item := range (stack) { fmt.Printf(%v ,item) } fmt.Printf(] ) } else { fmt.Println(Show:: The stack is empty) } }
The first go statement states the package name Stack’, which our code belongs to. Then we need to import a set of built-in or custom packages that are needed in our program; here, only the fmt package, required for formatted I/O, has been imported. Now, we have created a custom type Stack which is equal to a slice of integers. We have written three functions to operate on a stack — Push(), Pop() and Show(). The Push() function takes a Stack pointer and an integer item to push onto the stack. Since a slice, unlike an array, can grow indefinitely, we skipped the overflow check. The Pop() function takes a Stack pointer and an integer pointer item, where the popped item is returned. It returns a Boolean value to indicate the success or failure of the operation. The Show() function takes a stack of value type. It prints the values present in the stack to the console.
Now let’s see our main package, shown below:
$GOPATH/src/gostack/gostack.go // The code in this file belongs to the 'main' package package main // import our 'stack' and other required packages import ( "gostack/stack" "fmt" ) // The 'main' function, entry point of our program func main() { var myStack stack.Stack var item int // show the empty stack stack.Show(myStack) // try to pop from the empty stack if stack.Pop(&myStack,&item) { fmt.Printf("\nThe Popped item=%d\n",item) } // push 10,20 into the stack stack.Push(&myStack,10) stack.Push(&myStack,20) // show the stack stack.Show(myStack) // pop from the stack if stack.Pop(&myStack,&item) { fmt.Printf("\nThe Popped item=%d\n",item) } // show the stack stack.Show(myStack) }
The first line states the package name main’. Then we import two packages, previously written stack’ and built-in fmt’. Note that the custom packages stack’ name is mentioned relative to the $GOPATH/src directory and its the directory name of the package source, not the file name.First, we create a variable stack of stack type from the stack package. It takes the form of: <package-name>.<type-name>. One more variable item of the int type created for Pop() call. The rest of the code is self-explanatory. Now, lets compile and execute the program, as follows:
$ cd $GOPATH/src/gostack $ go build $ ./gostack Show:: The stack is empty Pop:: The stack is empty [ 10 20 ] The Popped item=20 [ 10 ]
We dont have class or inheritance in Go. We have methods and interfaces. Lets understand methods first. A method is a function associated with a particular type. We have changed our functions to methods by shifting the stack reference from the argument list to Go receiver notation just after the func keyword. So, the set of three methods Push(), Pop() and Show(), forms an interface. Any type having the same interface, i.e., set of methods with the same signature as these three, is type compatible in Go. An empty interface is represented by interface{}, which is satisfied by any type. Thats why we have changed our item type to interface{} from int so that our stack can handle any type of data this time. Now, we can treat our stack as an object rather than normal variable, and call the operations as methods rather than simple functions. In Go, multiple values can be returned from a function. The Pop() function is modified to take advantage of that. In case of a failure, apart from the popped item, we also return an error.
Now, lets modify the program to make it object-oriented in the Go way.
$GOPATH/src/gostack/stack/stack.go) // The code in this file belongs to the 'stack' package package stack import ( "errors" // import the 'error' package for error reporting "fmt" // import the 'fmt' package for displaying output ) // Create a 'Stack' type, which is a slice of interface{} type Stack []interface{} // 'Push' function to push item onto the stack given as receiver func (stack *Stack) Push(item interface{}) { *stack=append(*stack,item) } // 'Pop' function to pop item from the stack given as receiver func (stack *Stack) Pop() (interface{},error) { if len(*stack)==0 { // len() returns the no of elements in a slice return nil,errors.New("Pop:: The stack is empty") } // remove the last element from the slice in item item:=(*stack)[len(*stack)-1] // creates a new slice by taking the ele from first to second last *stack=(*stack)[:len(*stack)-1] return item,nil } // 'Show' function to display the content of the stack given as receiver func (stack Stack) Show() error { if len(stack)!=0 { fmt.Printf("[ ") for _,item := range (stack) { fmt.Printf("%v ",item) } fmt.Printf("] ") return nil; } else { return errors.New("Show:: The stack is empty") } }
We have changed our main accordingly. This time, we have used multiple assignment notations to copy the data as well as error value returned from Pop().
$GOPATH/src/gostack/gostack.go // the code in this file belongs to the main package package main // import our stack and other required packages import ( gostack/stack fmt ) // the main function, entry point of our program func main() { var myStack stack.Stack // show the empty stack if myStack.Show()!=nil { fmt.Println(Show:: The stack is empty) } // try to pop from the empty stack if item,err:=myStack.Pop(); err==nil { fmt.Printf(\nThe Popped item=%v\n,item) }else{ fmt.Println(Pop:: The stack is empty) } // push 10,20 into the stack myStack.Push(10) myStack.Push(20) // show the stack myStack.Show() // pop from the stack if item,err:=myStack.Pop(); err==nil { fmt.Printf(\nThe Popped item=%v\n,item) }else{ fmt.Println(Pop:: The stack is empty) } // show the stack if myStack.Show()!=nil { fmt.Println(Show:: The stack is empty) } }
Now, its time to add exception handling to our program. We have modified our Pop() method to demonstrate how exception handling works. We have panic() and recover() built-in functions. A detailed description of these functions is beyond the scope of this article. We will only describe our own use case here. If Pop() method is called on an empty stack, we generate a panic with a user-given message. By default, panic gets propagated through the call stack of functions. But, we want to capture it in the same function and handle it. At the beginning of the Pop() we have called an anonymous function, i.e., a function without name. But this doesnt get executed immediately because of the defer keyword. This is called a deferred function, which gets executed at the end of the function before returning to the caller. That means that just before leaving the Pop() function, we check if any panic has been generated, and if so, we print the panic message to the console.
$GOPATH/src/gostack/stack/stack.go // Pop function to pop item from the stack given as receiver func (stack *Stack) Pop() (item interface{},e error) { e=errors.New(Empty stack) defer func() { if ret:=recover(); ret!=nil { fmt.Printf(%v\n,ret) } }() if len(*stack)==0 { // len() returns the no of elements in a slice // call panic() with the error msg panic(Pop:: The stack is empty) } // remove the last element from the slice in item item=(*stack)[len(*stack)-1] // creates a new slice by taking the ele from first to second last *stack=(*stack)[:len(*stack)-1] return item,nil }
In the next article on Go, we will discuss concurrency support along with a suite to test a Go program.