Starting out with Go

I like learning different programming languages. Sometime I learn alternate ways to do things which might be useful in my usual language, sometimes I get a feel for how another language might be better for certain tasks and gives me more options for developing apps. I recently started learning the language Go, so this is my first of several posts on what I’ve learned.

Note: I’m literally just learning this, so I suspect any posts on the subject will be pretty basic, but hopefully, might be of use to others (as well as myself).

Why Go?

Probably the first question many of us might ask is why pick a specific language. For example, is the language all about speed, or writing application in a specific paradigm like a functional language.

So Why Go? Where does it fit into?

Before we look to answer that question, we should note that Go was designed by Google as an open source, compiled and statically typed language.

So we might view Go as a possibly modern take on C but with features, such as concurrency as primitives as well as being a garbage collected language. It’s cross platform and compiles to native. The language is a general purpose language, so it can do many things, but I’ve not found anything to suggest it’s aimed at GUI work. I’ve seen lots of talk about supporting distributed code, and services/microservices etc. but not yet done anything with these, so cannot confirm how good it is as such things.

Let’s get started and download Go

Okay, so you can read a brief history of Go from Wikipedia etc., let’s instead download Go and install it from Downloads.

On Windows (as I’m currently running it) by default the installation is into C:\Go and this is what the environment variable %GOROOT% should be set to (either during installation or manually assigned if need be).

You’ll need to set up the %GOPATH% environment variable (or via your preferred IDE, I’m using JetBrains Gogland (1.0 Preview)) to point to your workspace, i.e. where you’ll be writing your application(s) to. So, for example, C:\Development\GoglandProjects on my installation is where I’m writing my Go projects to at the moment.

Note: You do seem to be able to get away without a GOPATH.

Hello World

Yes, this one’s on The Go Programming Language website, but we’ll recreate here.

  • In your workspace create a HelloWorld folder
  • Create the file hello-world.go in your preferred editor
  • Type into the file, the following
    package main
    
    import "fmt"
    
    func main() {
       fmt.Println("Hello World")
    }
    
  • From a command prompt (within the workspace\HelloWorld folder) run
    go build hello-world.go
    

    or even simpler (if you’re in the code’s folder), just run

    go build
    

    This command compiled the Go code into a native EXE

At this point you’ll have a binary (hello-world.exe) that you can run or if you delete this and run the following line from the command prompt in your workspace

go run hello-world.go

then Go will compiled to a temporary EXE, i.e. no EXE is create in our workspace, it just runs the go code.

In the hello-world.go code, you’ll see standard looking constructs, for example we have an include/import/using type line which imports the fmt package, you have a func main, which is obviously a function/method (and should be in a package named main) and some call on the fmt package which ouputs to the console the string “Hello World”.

So all pretty recognisable.

Note: I mentioned fmt is a package and at first site this appears to be like an object/class, but Go is not an object oriented language. There’s no inheritance for example, or base object but there are constructs that can give us some OO like capabilities, instead of objects we have structures “struct” types like in C as well as interfaces.

Basics

Here’s a quick list of some of the basics we expect to see in a language.

Commenting

The standard C++ // and /* */ operators are used for single line and multi line comments respectively.

Namespace/Package

Analogous to a namespace, we have the package – for example

package fmt

Creating your own types

As mentioned, Go is not an OO language, but like C with typedef and struct we can create our own custom types, for example

type MyInteger int

or a struct using

type MyStructure struct {
	a MyInteger
	b MyInteger
}

Declaring variables

We define variables using the var keyword (like the optional usage in C#), i.e.

var myInteger = 3

In the case of situations where we want to declare the type. We declare the type after the variable name, i.e.

var myInteger MyInteger = 3

We could also use

var myInteger = MyInteger(3)

Note: Interestingly, declaring an unused variable results in a compile time error as does unused packages, this ensure you keep your code “clean” of anything not required.

Basic types

Ofcourse Go includes the basic types (see builtin.go) which include string, int, unit, byte, float, bool etc.

Loops

Ofcourse we for loops (see below), but interestingly no while loops

for i := 0; i < 3; i++ {
   fmt.Println("Hello")
}

with the := reminds me of a Pascal crossed with C style. Notice no parenthesis are required around the for loop but braces are required.

Also parenthesis must be placed (opening parenthesis {) on the same line as the loop (of if statements).

Using a for loop like a while loop just means writing the following

i := 0
for i < 3 {
   fmt.Println("Hello")
   i++
}

A while(true) infinite loop can be written as

for {
   fmt.Println("Hello")
}

Flow control with if..else and switch statements

if i % 2 > 0 {
   fmt.Println(strconv.Itoa(i) + " Odd")
}

We can also declare/assign variables as part of the if statement, for example

if isOdd := i % 2; isOdd > 0 {
   fmt.Println(strconv.Itoa(i) + " Odd")
}

else statements must be on the closing brace line and their opening brace on the same line also, for example

if isOdd := i % 2; isOdd > 0 {
   fmt.Println(strconv.Itoa(i) + " Odd")
} else {
   fmt.Println(strconv.Itoa(i) + " Even")
}

Switch statements are pretty much as per C# etc.

switch i % 2 {
case 0:
   fmt.Println(strconv.Itoa(i) + " Odd")
default:
   fmt.Println(strconv.Itoa(i) + " Even")
}

like if statements, we can also assign variables and test them after the switch keyword and before the opening brace.

Functions

As mentioned already, we create functions using the func keyword. Functions can take arguments and return values (as you’d expect). For example

func isOdd(i int) bool {
	return i % 2 != 0
}

Note: we declare the return type after the function (or no type for the equivalent of a void function) and we use the return keyword as per many C like languages.

We can pass multiple arguments into a function in the standard way

func doSomething(i int, test bool) bool {
// do something
}

we can also group arguments of the same type like so

func doSomething(a, b, c int) bool {
// do something
}

We’ve shown code returning a single value, but we can also return tuples easily using the following syntax

func doSomething() (string, string) {
	return "Hello", "World"
}

and assigning this we would have something like

a, b := doSomething()

We can create anonymous functions using the func() syntax, for example

func doSomething() func() string {
	return func() string {
		return "Hello World"
	}
}

will return a function which returns a string.

We can also pass variable arguments to a function (like vargs or params) using

func doSomething(args ...string) {
	for _, arg := range args {
		fmt.Println(arg)
	}
}

Note: in this example the _ is used as range returns a tuple of index (int) and the value (i.e. value[index]), The _ can be used in situations where we want to ignore a value and is special in that it will not cause an unused variable compile time error.

Anonymous and named returns

In the above we looked at declaring return values like this

func doSomething() (string, string) {
	return "Hello", "World"
}

in that the return (string, string) has no variable name associated with it, but we can also return named variables, for example

func doSomething() (a string, b string) {
	return "Hello", "World"
}

at this point the named returns only really demonstrate a use as a form of documentation, but they also get automatically initialized to the defaults for the type and can be used in a similar way to the out keyword in C#, i.e. we can assign to them.

Here’s an example

func doSomething() (a string, b string) {
	a = "Hello"
	b = "World"
	return
}

so here we assign the named return a value and then we must still use a return. This allows us to build up the return tuple during the flow of the function, instead of storing as a local variable until we return the tuple.

Arrays

Let’s end this post with arrays. The standard [] syntax is used, here we declare an array and initialize it

a := [2]string{"Hello", "World"}

arrays are base 0 index, hence

fmt.Println(a[0]) 

will result in Hello output to the console.

Package visibility

Functions and methods with a capitalized first letter (i.e. Pascal case) are public, whereas a lowercase first letter (i.e. Camel case) are private to the package.

In other words the public functions are visible globally whereas private are visible only within the package.

References

The Go Programming Language
Go by example