Why Go? A Hacker’s First Dive into Golang

Ever wondered why Go keeps popping up in modern toolchains and cloud-native stacks? Here’s a hands-on dive into the syntax, philosophy, and quirks of Golang; written from a hacker’s point of view.
Why Go? A Hacker’s First Dive into Golang

Introduction: Why learn Go (now)?

I've wanted to look into Go for a long time now, my cherry picker would greatly benefit from the performance boost Go offers. Let’s crack open this shiny new language and see what all the hype is about

Installation

"Go, or Golang, is a language that was developed by Google for in-house software development, to make their software easier to write, maintain and build." The installation is relatively straight-forward from https://go.dev/doc/install.

Interesting: https://www.jetbrains.com/go/ - of course jetbrains has it's own IDE for Go. I guess i'll use that one.


Using the Go Compiler

go build <FILENAME>.go

If we now type in the ls-command, besides the original Go program there'll be the executable file.

A (better) alternative: go run

go run <FILENAME>.go

go run is like go build's overachieving sibling; compiles and runs your code, then vanishes.

Hello World in Go

package main

import "fmt"

func main() {
    fmt.Println("Hello World")
}
Seems a bit like Python+Java doesn't it?

Packages in Go

Projects, possibly containgin many .go-files, can be organized into packages.

Each package is like a directory: .go-files related in their function/ purpose can go in one package (hehe got it, go).

So in bigger projects, we'll end up with like an io package, a api package and so on.

This is what the first line of our Hello World does: It is the package declaration, telling the Go compiler to which package this .go-file belongs.

If this package declaration is package main, then this program will be compiled into an executable.

Next up, we also import a package with import "fmt" - the package name needs to be enclosed with ".


Functions in Go

Above, we use the func keyword to declare the Go function main.

func denotes the start of a function declaration, followed by the name of the function (in our case main). After these come a pair of parantheses () and a set of curly braces {}.

The code is written inside the set of curly braces, just like you're used to from Java, Javascript, C, ...

The code inside a function is indented!
func main() {
    fmt.Println("Hello World")
}

Here we use the Println-function from the fmt-package from our earlier import to print out "Hello World"

Invoking Functions

When we write functions, we need to write code inside them to invoke them, otherwise they're unused. An exception here is the main function if it resides in the main-package: If so, this is a special case in Go. Upon compilation, an executable is produced - when run, the executable uses the main function as the entry point for starting.

Go seems to be case sensitive, println won't work instead of Println.

Packages overview

You can explore Go’s entire standard library right here, tons of hidden gems.
import (
  "package1"
  "package2"
)

imports are possible with these () or just separating with linebreaks

import (
  alias1 "package1"
  "package2"
)

This let's us define aliases, just like the import ... as ... in Python. alias1.SampleFunc() now equals package1.SampleFunc().

Seems you can't concat like

package main

import "fmt"
import t "time"

func main() {
    fmt.Println("Hello at " + t.Now())
}

we'll see soon how it's done right i guess.


Comments in Go

Don’t comment bad code, rewrite it.” - Brian W. Kernighan and P. J. Plaugher.

I love this quote when it comes up, you wouldn't believe how often in daily worklife i see prod code that a first-semester could write better.

Code quality isn't about being clever, it’s about being clear. If you find yourself writing a comment that says “what this line really does is…”, maybe rewrite the line instead.

You’ll thank yourself later.

// Oneline comments are possible just like
/*
block comments are, disregarding "special signs"
fmt.Println("This WON'T print")
*/

Go Resources

go doc <pacakge or command you want to know about>

#e.g.:
go doc fmt
go doc fmt.Println
package main

import (
  f "fmt"
)

func main() {
  fmt.Println("Current time:", time.Now())
  fmt.Println("  __      _")
  fmt.Println("o'')}____//")
  fmt.Println(" `_/      )")
  fmt.Println(" (_(_/-(_/")
}


Variables & Constants

var <NAME> type = value
# is synonyme to
<NAME> := value # Here, the type is compiler-inferred: the compiler decides the type
:= can only be used inside functions!

Plain initializing is also possible, with the variable defaulting to it's type's standard value:

var a string
var b int
var c bool
var a, b, c, d int = 1, 3, 5, 7

#block declaration:
var (
     a int
     b int = 1
     c string = "hello"
   )

are all valid!

Go variable naming rules

  • A variable name must start with a letter or an underscore character (_)
  • A variable name cannot start with a digit
  • A variable name can only contain alpha-numeric characters and underscores (a-z, A-Z, 0-9, and _ )
  • Variable names are case-sensitive (age, Age and AGE are three different variables)
  • There is no limit on the length of the variable name
  • A variable name cannot contain spaces
  • The variable name cannot be any Go keywords

Constants

const <CONSTNAME> type = value
You can create constants typed (declared with a type like const A int = 1) and untyped (declared without a type like const A = 1, again compiler-inferred).

Println and Formatting

Alternatives to Println regarding output

Our base program for now:

package main

import (
    "fmt"
)

func main() {
    var i, j string = "Cherry", "Picker"

    <PRINT_STATEMENT>
}
fmt.Print(i)
fmt.Print(j)

#leads to

CherryPicker

fmt.Print(i,j) has the equivalent output, we can use the commata-separation for any kind of concatenation, e.g. fmt.Print(i, " ", j).

If neither arguments are strings, a space is inserted by Print() between printed values. To automatically add whitespaces between arguments, we use the above Println().

There is much more to printing output here.

Go Formatting Verbs

Let's say for this that

var i = 16.7
var txt = "Cherry Picker."

With all data types you can use the following:

Format VerbExample CodeOutputExplanation
%vfmt.Printf("%v\n", i)15.5Default format for the value (float64)
%#vfmt.Printf("%#v\n", i)15.5Go-syntax format (also 15.5, but useful for complex types)
%v%%fmt.Printf("%v%%\n", i)15.5%Prints the value followed by a % sign
%Tfmt.Printf("%T\n", i)float64Prints the type of the value
%vfmt.Printf("%v\n", txt)Hello World!Default format for string
%#vfmt.Printf("%#v\n", txt)"Hello World!"Go-syntax format for string (includes quotes)
%Tfmt.Printf("%T\n", txt)stringPrints the type of the value

We're only getting started hehe:

Integer Formatting Verbs

VerbDescriptionExample Output
%bBase 2 (binary)1111
%dBase 10 (decimal)15
%+dBase 10 with sign+15
%oBase 8 (octal)17
%OBase 8 with 0o prefix0o17
%xBase 16 (hex), lowercasef
%XBase 16 (hex), uppercaseF
%#xBase 16 with 0x prefix0xf
%4dRight-justified with width 415
%-4dLeft-justified with width 415
%04dZero-padded with width 40015

String Formatting Verbs

VerbDescriptionExample Output
%sPlain stringHello
%qDouble-quoted string"Hello"
%8sRight-justified string, width 8Hello
%-8sLeft-justified string, width 8Hello
%xHex dump of byte values (lowercase)48656c6c6f
% xHex dump with spaces between bytes48 65 6c 6c 6f

Boolean Formatting Verbs

VerbDescriptionExample Output
%tBoolean value (true / false)true, false

Float Formatting Verbs

VerbDescriptionExample Output
%eScientific notation (e.g., 1.23e+06)3.141000e+00
%fDecimal point, no exponent3.141000
%.2fDecimal format, 2 digits precision3.14
%6.2fWidth 6, 2 digits precision (padded left)3.14
%gCompact: uses exponent only when necessary3.141

Go Data Types

Bool

package main
import ("fmt")

func main() {
    var a bool = false
    var b int = 40000
    var c float32 = 31.392
    var d string = "Lupercal!"

    fmt.Println("Boolean: ", a)
    fmt.Println("Integer: ", b)
    fmt.Println("Float:   ", c)
    fmt.Println("String:  ", d)
}

straight-forward right? Not necessarily, W3Schools has a really interesting example for this:

// inside our main:
var v1 bool = true
var v2 = true
var v3 bool
b4 := true

Now we print out all of them - what do you think will each one give out?

  • [ ] true, true, true, true
  • [x] true, true, false, true
  • [ ] false, false, true, false
  • [ ] true, false, true, false

No interaction in my site yet hmm.. a slight spoiler for the answer here.

Declaration Comparisons

var v1 bool = true // typed declaration with initial value: clear
var v2 = true // untyped declaration with initial value: compiler-inferred type again
var v3 bool // typed declaration without initial value: standard-value of bool is false (like in Java)
b4 := true // untyped declaration with initial value: compiler-inferred with walrus operator

Integer

Just as in other languages, we've got

  • Signed integers - able to store both positive and negative values
  • Unsigned integers - able to store only positive values

Signed integers are divided into int (might be 32 or 64 as standard), int8int16int32int64 - business as usual. Same for unsigned, except called uintuint8, ...

Float

As usual, the distinguishment is made between float32 and float64 - float64 is default.
package main
import ("fmt")

func main() {
  var x float32 = 123.78
  var y float32 = 3.4e+38
  fmt.Printf("Type: %T, value: %v\n", x, x)
  fmt.Printf("Type: %T, value: %v", y, y)
}

See how, just like your calculator may have shown you some time, you can use scientific parameters such as e, for small floats.

String

Earlier we wanted to know more about string concatenation.
package main

import (
    "fmt"
    "strings"
)

func main() {
    first := "Hello"
    second := "World"

    // 1. Using + operator
    combined1 := first + " " + second
    fmt.Println("Using +:", combined1)

    // 2. Using fmt.Sprintf
    combined2 := fmt.Sprintf("%s %s", first, second)
    fmt.Println("Using fmt.Sprintf:", combined2)

    // 3. Using strings.Join
    combined3 := strings.Join([]string{first, second}, " ")
    fmt.Println("Using strings.Join:", combined3)

    // 4. Using a String Builder (efficient for many strings)
    var builder strings.Builder
    builder.WriteString(first)
    builder.WriteString(" ")
    builder.WriteString(second)
    combined4 := builder.String()
    fmt.Println("Using strings.Builder:", combined4)
}

Summary

  • + is simple and direct.
  • fmt.Sprintf is flexible for formatting.
  • strings.Join is great for slices.
  • strings.Builder is best for performance in loops or large concatenations.
Now we've got the basics covered. Next post, we'll go into more advanced concepts in Go. Drink enough water today!
Subscribe to my monthly newsletter

No spam, no sharing to third party. Only you and me.

Member discussion