The Go language was created in 2007. The main “culprit” behind its birth was Google – the corporation’s developers were dissatisfied with the existing coding languages (especially C++). The basic idea behind Go was to combine the best aspects of other technologies, like C or JavaScript, while eliminating some of their problems at the same time.
Go is a statically typed programming language, with very good readability and usability (in these respects, it resembles Python and JavaScript). It’s characterized by high-performance networking and multiprocessing – in fact, that second feature was one of the main reasons for the language’s creation.
It’s worth mentioning that Go is one of the most loved programming languages – in the StackOverflow’s 2020 Developer Survey, it took 5th place with a score of 62,3% (a year before, it was 10th, which means it gained a lot of positive attention and praise in the last twelve months).
It was one of the most important things for Go’s developers and it’s the reason why they’re so stubborn when it comes to further development of this solution – they’re reluctant to add new functionalities when there are other ways to achieve the same effect.
Go consists of several different packets and you can manage your application through them – you add new functionalities by importing packets.
The language has a very powerful and functional standard library, with packets for the most common coding scenarios.
Go is a statically typed programming language, which means the compiler checks the type conversion and compatibility. Therefore, you can avoid problems that often arise in the case of dynamically typed languages.
Go supports unit testing and it’s very easy to write both the tests themselves and any needed documentation.
Go is independent of the platform and can be used on any server because the code is compiled and converted into binary.
Let’s talk a bit about syntax and some examples of how the language is used. A simple “Hello, world!” in Go looks like this:
1
2
3
4
5
|
package main
import “fmt”
func main() {
fmt.Println(“Hello, world!”)
}
|
As you can see, it’s pretty simple. You only need to import one packet – “fmt” – which allows us to print “Hello, world!” in the console. Looks a bit like in Python, doesn’t it?
Declaring variables works a little bit like in Java, except you don’t have to specify the variable’s type. Go should be able to figure it out. Also, variables aren’t segregated – you don’t have to use a single type of them in a given line of code. Look at the example below, where I’ve used three different kinds, one after the other.
1
2
3
4
5
6
7
8
|
package main
import “fmt”
func main() {
var i, j int = 1, 2
k := 3
c, python, java := true, false, “no!”
fmt.Println(i, j, k, c, python, java)
}
|
There are also constants in Go – you define them by inserting the word “const” before the variable, as seen in the following example.
1
2
3
4
5
6
7
8
9
10
|
package main
import “fmt”
const Pi = 3.14
func main() {
const World = “世界“
fmt.Println(“Hello”, World)
fmt.Println(“Happy”, Pi, “Day”)
const Truth = true
fmt.Println(“Go rules?”, Truth)
}
|
Functions also resemble what we know from Java – the difference is you have to use the “func” prefix before each one. You have to specify the name, the type of the transferred variable, as well as the type of the returned variable. Here, the difference between Go and Java is that in the case of the former there can be many returned values – it doesn’t have to be just one (e.g., an object).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package main
import “fmt”
func add(x int, y int) int (
return x + y
}
func main() {
fmt.Println(add(42, 13))
}
package main
import “fmt”
func swap(x, y string) (string, string) {
return y, x
}
func main () {
a, b := swap(“hello”, “world”)
fmt.Println(a, b)
}
|
The “for” loop also looks a lot like in Java, the exception being some missing brackets in the place where you define the condition.
1
2
3
4
5
6
7
|
func main() {
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
}
|
The same goes for the “if” loop, but in that case, you can also add a declaration and calculation of a variable based on which the condition should be checked.
1
2
3
4
5
6
|
func pow(x, n, lim float64) float 64 {
if v := math.Pow(x, n); v < lim {
return v
}
return lim
}
|
And finally the “switch” loop. There’s no “break” here – Go always checks the type it wants and that type is displayed. If there’s no “break”, it doesn’t check all of them.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
func main() {
fmt.Println(When’s Saturday?”)
today := time.Now().Weekday()
switch time.Saturday {
case today + 0:
fmt.Println(“Today.”)
case today + 1:
fmt.Println(“Tomorrow.”)
case today + 2:
fmt.Println(“In two days.”)
default:
fmt.Println(“Too far away.”)
}
}
|
When it comes to the programming language’s data structure, in Go we have pointers, structs, arrays/slices, and maps.
Pointers work more or less like in C and C++ – they… well, they point, as the name suggests. But to be precise, they point to a place in memory, instead of a specific value, which can be helpful, because just like in Java, it’s the value, not the reference, that is transferred to the function (unless we transfer a pointer).
1
2
3
4
5
6
7
8
9
10
11
|
func main() {
i, j := 42, 2701
p := &i // point to i
fmt.Println(*p) // read i through the pointer
*p = 21 // set i through the pointer
fmt.Println(i) // see the new value of i
p = &j // point to j
*p = *p / 37 // divide j through the pointer
fmt.Println(j) // see the new value of j
}
|
Structs resemble a solution you can find in C++, and in Go they’re used to do similar things – the struct type aggregates any number of variables.
1
2
3
4
5
6
7
|
type Vertex struct {
X int
Y int
}
func main() {
fmt.Println(Vertex(1, 2))
}
|
In Go we have just a single type of a table, which always has to have a set value. Here’s what it looks like:
1
2
3
4
5
6
7
8
9
|
func main() {
var a [2]string
a[0] = “Hello”
a[1] = “World”
fmt.Println(a[0], a[1])
fmt.Println(a)
primes := [6]int{2, 3, 5, 7, 11, 13}
fmt.Println(primes)
}
|
There’s also something called a slice – the easiest way to look at it is to see it as a part of a bigger table. If you modify the slice, you’ll also affect the table it came from. The tool is often used as a dynamic table, because a slice can have a higher value than the default table. It looks like this:
1
2
3
4
5
|
func main() {
primes := [6]int(2, 3, 5, 7, 11, 13)
var s [] int = primes[1:4]
fmt.Println(s)
}
|
The last important element of Go’s data structure are the maps. They work like in Java – they have a key-value structure. The syntax is very simple:
1
2
3
4
5
6
7
8
9
10
11
|
type Vertex struct {
Lat, Long float64
}
var m = map[string]Vertex{
“Bell Labs” : {40.68433, –74.39967},
“Google”: {37.42202, –122.08408},
}
func main() {
fmt.Println(m)
}
|
The most interesting thing that you can find in Go are Goroutines and Channels.
Goroutines work in a way similar to koroutines you might know from Kotlin, which is to say they’re a way to create a very light thread. You can do that by adding the prefix “go” to the function you want to execute in a given thread.
1
2
3
4
5
6
7
8
9
10
|
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say(“world”)
say(“hello”)
}
|
Channels are used as an intermediary to transfer data between Goroutines. You can assign a certain value to the channel and you can then read it from it. This is one of the ways to synchronize Goroutines and threads.
1
2
3
4
5
6
7
8
9
10
11
|
func main() {
// make a new channel
messages := make(chan string)
go func() {
// write to channel
message <– “Hello World!”
}()
// read from channel
message := <–messages
fmt.Printf(“I got the message %s”, message)
}
|
I’ll now show you a couple of examples of using the Go programming language in my work.
Let’s start with transactions between databases. The important thing is that you have to ensure transactivity. Like I said before, Go is a pretty simple language, so you have to control everything yourself. You need to create a connection to the database, create context, start the transaction, execute whatever query you want, and then end the transaction with “Commit” or “Rollback”.
Another example – here’s how you can create a small REST API very fast (for example, a mock for a service you use and can’t access at the moment). In Go, it takes just a little while. You just need to add a library that’ll be responsible for HTTP communication. Using this library, you set up a server that’ll listen to port 8080, and if that port gets called, a certain message is displayed (depending on the type of request). There are also Mutex libraries that offer more control, but if you’re after something that can be done quickly and easily, that’s how you can achieve it:
You can write unit tests very quickly and easily. The only requirement the function testing your functionality needs to meet is being able to get a “testing” variable. What you need to know when it comes to Go and testing is that you need to check the condition yourself – there are no assert libraries that would do this for you.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package main
import “testing”
func TestSum(t *Testing.T) {
tables := [ ]struct {
x int
y int
n int
}{
{1, 1, 2},
{1, 2, 3},
{2, 2, 4},
{5, 2, 7},
}
for _, table := range tables {
total := Sum(table.x, table.y)
if total != table.n {
t.Errorf(“Sum of (%d+%d) was incorrect, got: %d, want: %d.”, table.x, table.y, total, table.n)
}
}
}
|
Here’s what would happen if – in the above function’s example – you swapped summation for multiplication:
Like many developers at Pretius, I work with Java on a daily basis, so when I started testing Go, it was natural for me to compare the two languages. The conclusions are interesting.
There aren’t that many, to be honest:
Differences are a much broader subject:
Go is a very good option when you work on following things:
Here are several examples of companies that already use Go:
Here’s where my tutorial ends. I hope you learned something useful about the basic structure and usage of Go. And hopefully, thanks to my Go vs Java comparison, you now know whether Google’s programming language is something you might be interested in. If you need more information, check the following resources.
Pretius has a great team of Java developers, and a lot of experience with using the technology in enterprise-grade systems. We also know our way around many different industries. Drop us a line at hello@pretius.com (or use the contact form below). We’ll get back to you in 48 hours and tell you what we can do for you.