Golang seems to be getting quite popular as its the programming language of choice for some cool new technology like Docker, Kubernetes, and OpenShift. Luckily enough, they’re all opensource too which means we can all contribute to these communities and get involved. One particularly awesome benefit of opensource that turns out to be extremely valuable and helpful in many circumstances is the obvious one: open source. I cannot tell you how often I’ve had to jump into the source of a project, regardless of the programming language used to implement it, to really understand what it’s doing or even more important: why it’s not doing something the docs say it should (or when there are no docs). Code is read far more often than it’s written, so it helps to understand how to read it.
Here are a few of the key pieces that stood out for me at first. Feel free to Tweet (@christianposta) me others you feel could be added here, or leave a comment. This article is certainly not meant to be an introduction to Go nor is it a complete Java->Go mapping. The purpose of the article is to quickly help Java developers understand a handful of common Go idioms in terms of how that maps to Java.
It appears that a common convention for Golang projects is to have all cli binary source files, or those in a “main” package,
placed in the
cmd folder which is at the root of the source tree. Packages that implement a lot of the functionality and
represent organizing cohesive sets of Types, constants, variables and functions, can usually be found in the
folder in the root of the source directory.
Golang organizes its code into packages, similarly to Java. You declare which package a source file is in (and all of
its constants, types, functions, etc) by typing
package <package_name> at the top of the source file; however,
unlike Java, you don’t put the full path (directory location), just the name. Example:
So if you have a package “api/endpoints” you’d have that directory structure on the filesystem (eg ./pkg/api/endpoints)
endpoints package would be declared in source files under the
endpoints directory, but they’d look like this:
We can import packages, just like we do in Java with the following:
We can use packages within the source code based on the last package name in the package path. For example, in the
above example, we import
k8s.io/kubernetes/pkg/auth/user and from with the code we can refer to the elements
inside that package with
user.Foo(). If we want to rename the package within our source file so it doesn’t
collide with other names, we can do what we did above:
And refer to the
errors package within our source code as
main package is where golang looks to find the entrypoint of the application. The
main package must have
main() function that takes no arguments and provides no return values:
As aforementioned, this package is usually found in the
cmd folder in the root directory.
Scope/visibility of types, constants, functions
In golang, to provide visibility scope to a struct/type/function/variable, to be exposed outside of a package,
the first character in the symbol is significant. For example, within a package
foo, if you have a function named
func Bar(), then because “Bar” has an upper-case first letter, it will be usable outside of the package. If you import
foo package, you’ll be able to access
foo.Bar(). If “bar” was lowercase, it would be hidden – that is, the case
of the first letter determines visibility
Methods can return multiple values
A function or method in golang (there is a distinction) can return a “tuple” or multi-value return. For example, calling a function that returns multiple values looks like this:
Classes, structs, methods
In Java we have Classes, but in Go we have structs. Structs can have methods on them, so they are kinda like classes.
This is a data structure named “Rectangle” that has two fields:
height. We can create a new
Rectangle like this:
and we can refer to its fields like this:
We can write methods on a Struct that operates on the fields of the struct like this:
So if you see idioms like this in golang code, think “Java classes”
Golang purposefully doesn’t have a “extends” type like Java does. Inheritance is done via composition (kinda like we should do that in Java as a “best practice” anyway :) ) However, it does look a lot like the “extends” keyword in Java in terms of how it’s visible to the programmer. For example:
In this example, Rectangle has an anonymous field of type
Shape. Whatever fields and methods
Shape have will be
One thing to note, however, is that just because
Shape, this is not like in Java where we could
pass in a
Rectangle to a function that takes a
Shape as a parameter. This would fail in Go. To get that type
of “type” polymorphism, you should use Go interfaces (next section)
Polymorphism, interfaces, and duck typing
In Java, we have specific interface types which specify behavior based on the methods that must be implemented by classes that claim to be that type. In Go, we do have intefaces that do the same thing, but classes don’t actually declare that they’re going to implement them specifically: they just implement the methods and then they fit that Interface.
For example this interface declares a Shape type that has Print() method:
However, when we create our Structs, we don’t have to declare this at all with “implements” like we do in Java: we just implement the methods and they can be passed to functions and treated as that type:
In this case, the Rectangle object could be passed to functions that expect a
Shape type because it implements
all of the methods for that type.
An example for-loop with go:
However, when iterating of an array (or something that looks like an array eg, string, map, slice, etc), you can
use the range operator like this (assume
foo is a list of strings):
If you need to know the index of the list as you iterate through it, looks like this:
Go does not have while loops, or do-while, or foreach, etc. You just use the for loop again like this:
Or can do an infinite while loop:
Pointers and reference
Golang uses pointers and references explicitly whereas Java mostly hides that. For example, in Java we could do
Shape shape = new Shape() and then
shape.foo() but in Go, we have to take care of the pointers directly:
When the main function ends, the rectangle
r would have the value width=5 and height=10 as you would expect.
Take note, we have to make explicit references to the pointers.
Golang is a garbage collected language; no need to explicitly release memory yourself (I know what you were thining whe you saw the pointers and references section above :)).
If you’re a Java developer and would like to add more to this please feel free to let me know (@christianposta)! Or if you’re a go-lang developer and I’ve misstated something here, please correct me! Hope this is helpful…