Note: Here's another guest post from our friends at the Hybrid Group.
So you're a Ruby developer and you've heard about this cool new language called Go, but you don't know where to get started. You've read the bullet points and got a litle scared. Static typing? Compiling? Is this the 80's all over again?! Well sorta! Go gives us the power of concurrent operations with a built in GC, so we get the power of a compiled language, but the lazyness of a dynamic language. Interested yet? Let's get into the basics of the language and cut out all the uncessary exposition and look at some code.
Here's the canonical "Hello world" in Go.
And its ruby equivalent
At first glance you may think "Wow that's verbose!", but if you have a c/c++/java background, this doesn't look too out of the ordinary. Now let's discect this program and firgure out what's going on.
package keyword identifies the scope of the code you're writing to the Go environment. Since we're not writing a library, our
package has to be
main, so that Go can execute this code when you run your generated executable.
import function pulls in external packages to be used in your program. The
fmt package is the standard package used for formatted IO operations.
Now we get to the
main() function. If you've written a C program before, you know you'll need a
main() function as the initial entry point for your programs execution. The
main() function in Go serves the same purpose. If you're not writing a library for later use, you need a
main() function in order for your Go program to actually run and do something.
Finally we get to the point where are program actually does something! The line
fmt.Println("Hello world!") calls the
Println function and prints
Hello world! to the console. Calling an external package's functions follows the same format,
That's all there is to a Go program!
Variable definitions in Go are pretty much like every other programming language ever, with the exception that they come in two flavors.
There's the implicit type instantiation
This creates a variable
s as a type
string and gives it the value
Hello World!. This is straightforward, but what if you want to create a variable for later use? Go has another way of defining variables.
This will create an int array which is scoped outside of the
for loop, so any changes to
arr within the
for loop persist in the scope of the function in which the
for loop resides.
arr = append(arr, n) is calling the builtin
append function which takes an array,
arr, and appends
n to the provided array. It then returns a new array with contents of
n pushed on at the end.
Easy stuff, right?
Go only has 3 control structures,
switch. Wait a minute, only 3? Yes!
if statement is your standard fare
for statement on the other hand is much more interesting. Instead of having all sorts of
each loops, Go has one
for loop which allows a few different forms.
The first form is your standard "iterate until false"
Another form is sorta like a while loop
And the last form is like an
each_with_index do sorta thing
which is ruby would be
And last, there's the
switch statement which is pretty much exactly how you would imagine it to be
There are more variations and nuances to these control structures, so be sure to consult the Go documentation on their specifics.
Functions in Go are first class. A first class function is a function which you can define and pass to another function for execution at a later time.
Let's look at a function definition.
If you come from the c/c++/java world, this function defition may look backwards to you. The variables types are defined after the variable name with the return type at the end of the function signature. So this function accepts two parameters, one string one int and returns a bool.
Now what about closures? Go has got you covered there!
Notice the extra
() at the end of the function definition, that means that the function should execute immediately. Now what if you wan to pass a function and execute it at a latter time. Won't that be interesting!
In the above example I define a function and assign it to the variable
f. I then pass it to the function
ExecuteMyFunction which expects a variable of type
func() and then using the
() on my variable, it is now executed.
Go isn't an object oriented language. Instead they have the concept a struct and structs have functions attached to said struct. You then create an instance of that struct and then have access to that structs functions and variables. Here's a simple Go program with an equivalent ruby example.
In the Example above I define a struct with the syntax
type Beer struct. This creates a struct of type
Beer. Congratulations, you've just created a new type in Go! A struct definition has a list of variable names with their types, and to assign function to a struct you simple add a
(b Beer) in between the
func keyword and the name of the function. Think of the
(b Beer) as the
self keyword. Any function with the
(b Beer) is only accessible to an instance of the
You may be thinking "What about private methods and variables?" You're absolutely right! The way Go defines private functions and variables is quite easy. All you need is a lower case letter at the beginning of the variable/function name and it's now private!
As you can see in the example above the
Person struct has the private variable
ssn as well as the private function
superSecretFunction are only to available the
Person struct itself, so the user has no direct access to that information. Neat!
Enter the goroutine
Now we're getting into the real power of Go. If you've tried to program concurrently in ruby, you have undoubtedly lost a few hairs. There are good libraries such as Celluloid for concurrent programming, but wouldn't it be awesome if there were language primitives which did it all for you? Luckily Go has got you covered!
Go makes it so easy to do a concurrent operation, all it requires is the
go keyword in front of your function call, and you're done. Super easy.
Sure that looks easy enough, but how do you share data between goroutines in a safe way? Channles my friend, it's all about goroutines and channels. Channels comes in two flavors, unbuffered and buffered. Unbuffered channels will block on writing to the channel, until the channel has been cleared. Whereas a buffered channel will queue up channel messages until you hit your defined buffer size, then it will block.
In this example I will call a function which which randomly sleeps for a duration, but I want to know how long my function slept for. Using an unbuffered channel, I can retrieve those sleep times just after they happen.
As you can see Go is a power language, especially for concurrent operations. If this quick overview has wet your appetite, you should head over to the tour of go which will go into more detail about the concepts I've outlined here.
Oh and do yourself a favor and run
go fmt on your project before you commit it to github. Go has fantastic tools to format your code with the Go standard indentation and white space practices.