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)
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