 
  
    
    
    
 
  
Why Go? A Hacker’s First Dive into Golang
Table of Contents
🧭 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 like a polite ninja. 🥷
  💬 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.
funcdenotes the start of a function declaration, followed by the name of the function (in our casemain). 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,
printlnwon’t work instead ofPrintln.
📦 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(" (_(_/-(_/")
}
☕ Like this write-up?
If this helped you, or if you just enjoy well-documented CTF journeys, consider supporting me.
  
  
  
  
     
  
🛠 Every coffee helps fuel more content like this — cheatsheets, walkthroughs, and more hacker-fueled documentation.
🔗 Visit: ko-fi.com/niklasheringer
🧠 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 likeconst A = 1, again compiler-inferred).
const (
  A int = 1
  B = 3.14
  C = "Hi!"
)
🧵 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 abovePrintln().
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 Verb | Example Code | Output | Explanation | 
|---|---|---|---|
| %v | fmt.Printf("%v\n", i) | 15.5 | Default format for the value ( float64) | 
| %#v | fmt.Printf("%#v\n", i) | 15.5 | Go-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 | 
| %T | fmt.Printf("%T\n", i) | float64 | Prints the type of the value | 
| %v | fmt.Printf("%v\n", txt) | Hello World! | Default format for string | 
| %#v | fmt.Printf("%#v\n", txt) | "Hello World!" | Go-syntax format for string (includes quotes) | 
| %T | fmt.Printf("%T\n", txt) | string | Prints the type of the value | 
We’re only getting started hehe:
Integer Formatting Verbs
| Verb | Description | Example Output | 
|---|---|---|
| %b | Base 2 (binary) | 1111 | 
| %d | Base 10 (decimal) | 15 | 
| %+d | Base 10 with sign | +15 | 
| %o | Base 8 (octal) | 17 | 
| %O | Base 8 with 0oprefix | 0o17 | 
| %x | Base 16 (hex), lowercase | f | 
| %X | Base 16 (hex), uppercase | F | 
| %#x | Base 16 with 0xprefix | 0xf | 
| %4d | Right-justified with width 4 |   15 | 
| %-4d | Left-justified with width 4 | 15   | 
| %04d | Zero-padded with width 4 | 0015 | 
String Formatting Verbs
| Verb | Description | Example Output | 
|---|---|---|
| %s | Plain string | Hello | 
| %q | Double-quoted string | "Hello" | 
| %8s | Right-justified string, width 8 |    Hello | 
| %-8s | Left-justified string, width 8 | Hello    | 
| %x | Hex dump of byte values (lowercase) | 48656c6c6f | 
| % x | Hex dump with spaces between bytes | 48 65 6c 6c 6f | 
Boolean Formatting Verbs
| Verb | Description | Example Output | 
|---|---|---|
| %t | Boolean value ( true/false) | true,false | 
Float Formatting Verbs
| Verb | Description | Example Output | 
|---|---|---|
| %e | Scientific notation (e.g., 1.23e+06) | 3.141000e+00 | 
| %f | Decimal point, no exponent | 3.141000 | 
| %.2f | Decimal format, 2 digits precision | 3.14 | 
| %6.2f | Width 6, 2 digits precision (padded left) |   3.14 | 
| %g | Compact: uses exponent only when necessary | 3.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
-  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), int8, int16, int32, int64 - business as usual.
Same for unsigned, except called uint, uint8, …
Float
As usual, the distinguishment is made between
float32andfloat64-float64is 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.Sprintfis flexible for formatting.
- strings.Joinis great for slices.
- strings.Builderis 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!