0%
Reading Settings
Font Size
18px
Line Height
1.5
Letter Spacing
0.01em
Font Family
Table of contents

Hello Golang: My First Steps to the Language
Software Engineer
Software Engineer

I’ve worked with Ruby, a programmer’s best friend for its clean and near natural-language syntax, and with JavaScript/TypeScript, which lets you learn once and build anything: backend, frontend, desktop, or even mobile apps. In university, I also used C++ for data structures and algorithms, and Python for training AI models.
Each language has taught me something new. There’s no need to argue which one is the best. Each has its own strengths and use cases. Recently, I noticed Go (Golang) becoming more popular in the job market for good reasons, so I decided to learn it.
Each language has taught me something new. There’s no need to argue which one is the best. Each has its own strengths and use cases. Recently, I noticed Go (Golang) becoming more popular in the job market for good reasons, so I decided to learn it.
When I start learning a new programming language, it helps to begin with its core principles: whether it’s compiled or interpreted, statically or dynamically typed, how it manages memory, how it passes data (by value or by reference), ... and what makes it different from what we already know. That mindset comes from a university subject I once learned: Principles of Programming Languages. It trained me to look beyond syntax and understand how each language is designed to think.
1. Go’s Nature
Go is a statically typed, compiled language created at Google. It was designed to solve Google’s real-world problems: building large-scale, high-performance systems while keeping codebases clean and easy to maintain.
Go’s philosophy is simple: fast build, fast run, fewer surprises. It aims to combine C’s performance and efficiency with Python’s readability and developer productivity.
Go’s philosophy is simple: fast build, fast run, fewer surprises. It aims to combine C’s performance and efficiency with Python’s readability and developer productivity.
Here’s what stands out:
- Static typing: Go checks types at compile time, not runtime — catching many errors early before your code ever runs. Despite being statically typed, Go’s type inference (
:= ) keeps syntax concise. - Compiled: When you run
go build , your entire program (including dependencies) compiles into one static binary. No virtual machine, no interpreter, no dependency hell, just a single executable that runs anywhere. - Memory management: Go provides automatic garbage collection like Java or Python, but it’s optimized for low latency.
- Concurrency: Go’s signature feature makes it simple to handle multiple tasks at once.
- Simplicity by design: Go avoids complexity: no inheritance, no implicit behavior, no hidden magic. Everything is explicit, predictable, and easy to read.
- Composition over inheritance: Instead of class hierarchies, Go encourages small, composable types you can combine freely.
- First-class tooling: Tools like
gofmt ,go test , andgo mod are part of the language itself, enforcing consistency and speeding up development.
2. Setting Up the Environment
We can follow the official installation guide here:
Once installed, check our version:
// language: bash go version
Initialize a new project:
// language: bash mkdir myfirstgo && cd myfirstgo go mod init myfirstgo
Then create a simple
// language: bash go run main.go
Everything in Go starts from the
// language: bash go build
3. Variables
Variables
Go supports both explicit and inferred variable declarations:
// language: go var message string = "Hello, Go!" count := 3 // inferred type: int
The var keyword lets us declare variables with explicit types, while := provides a shorthand declaration with automatic type inference.
Go’s basic types include:
- Integers (int, int64)
- Floating-point numbers (float32, float64)
- Strings (string)
- Booleans (bool)
4. Data Collections
In Go, data collections are handled through arrays, slices, and maps.
Array
An array has a fixed size — once created, it cannot grow or shrink.
// language: go var nums [3]int nums[0] = 10 nums[1] = 20 nums[2] = 30 fmt.Println(nums) // [10 20 30]
We can also declare and initialize an array in one line:
// language: go arr := [3]string{"Go", "Rust", "Python"} fmt.Println(arr[1]) // Rust
Arrays are rarely used directly in Go because their size is static. That’s where slices come in.
Slice
A slice is a flexible, dynamic view of an array — we can append, cut, and grow it easily.
// language: go langs := []string{"Go", "Ruby"} langs = append(langs, "Python") fmt.Println(langs) // [Go Ruby Python] fmt.Println(len(langs)) // 3
We can also slice existing data:
// language: go nums := []int{10, 20, 30, 40, 50} fmt.Println(nums[1:4]) // [20 30 40]
Slices are built on top of arrays but provide much more convenience. They’re used in most real Go code.
Map
A map is a key-value store, similar to dictionaries in Python or hashes in Ruby.
// language: go scores := map[string]int{ "Alice": 90, "Bob": 85, } fmt.Println(scores["Alice"]) // 90 // Add new value scores["Charlie"] = 92 // Check existence value, ok := scores["Bob"] if ok { fmt.Println("Bob's score is", value) }
We can delete keys with:
// language: go delete(scores, "Alice")
5. Control Flow
If-else
// language: go if x > 0 { fmt.Println("positive") } else if x < 0 { fmt.Println("negative") } else { fmt.Println("zero") }
Switch-case
// language: go switch day := "saturday"; day { case "saturday", "sunday": fmt.Println("Weekend") default: fmt.Println("Weekday") }
Go automatically breaks after each case, and the default case is optional.
All loops in Go use the
// language: go for i := 0; i < 5; i++ { fmt.Println(i) }
We can also use
// language: go langs := []string{"Go", "Ruby", "Python"} for index, value := range langs { fmt.Println(index, value) }
6. Functions
Let’s define a function:
// language: go func add(a int, b int) int { return a + b }
Go can infer types in some cases, but function parameters and return types are usually declared explicitly for clarity.
We can also return multiple values:
// language: go func divide(a, b float64) (float64, error) { if b == 0 { return 0, fmt.Errorf("division by zero") } return a / b, nil } func main() { result, err := divide(10, 0) if err != nil { fmt.Println("Error:", err) } }
This (value, error) pattern is very common in Go. Instead of using exceptions, Go encourages explicit error handling, which makes programs more predictable.
Pass by Value and Reference
Go passes all arguments by value. However, slices , maps contain internal references, so changes made inside a function can affect the original data. Arrays , on the other hand, are copied entirely, so modifying them doesn’t affect the original.
// language: go func modifyArray(arr [3]int) { arr[0] = 99 } func modifySlice(slice []int) { slice[0] = 99 } func main() { numsArray := [3]int{1, 2, 3} modifyArray(numsArray) fmt.Println(numsArray) // [1 2 3] — unchanged numsSlice := []int{1, 2, 3} modifySlice(numsSlice) fmt.Println(numsSlice) // [99 2 3] — changed }
7. Modules and Packages
Every Go file begins with a package declaration. We can organize our code like this:
myfirstgo/ ├── main.go └── utils/ └── math.go
math.go
// language: go package utils func Square(x int) int { return x * x }
main.go
// language: go package main import ( "fmt" "myfirstgo/utils" ) func main() { fmt.Println(utils.Square(5)) }
Running go run . automatically finds and compiles all packages within the module.
In Go, visibility (or exporting) is controlled by capitalization, not by keywords like public or private.
In Go, visibility (or exporting) is controlled by capitalization, not by keywords like public or private.
- Exported identifiers (visible outside their package) start with a capital letter.
- Unexported identifiers (private to the same package) start with a lowercase letter.
// language: go package utils // Exported: accessible from other packages func Add(a, b int) int { return a + b } // Unexported: only usable inside the utils package func subtract(a, b int) int { return a - b }
8. Start Solving a Simple LeetCode Problem with Go
After reviewing some basic Go syntax, we’ll start with a simple LeetCode problem. It’s easy to forget everything we’ve just learned if we only read about it. We need to write code and use it in practice.
Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
You can return the answer in any order.
Example 1:
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].
My first draft solution is:
// language: go func twoSum(nums []int, target int) []int { // key is number, value is index numMap := map[int]int{} for index, num := range nums { rest := target - num if numMap[rest] != nil { return []int{index, numMap[rest]} } numMap[num] = index } return []int{} }
It causes errors because:
numMap[rest] returns an int, so comparing it to nil is invalid (since I'm familiar with JavaScript). Go uses this syntax
// language: go if value, ok := numMap[rest]; ok { // do sth }
- Return
return {index, restIndex} is invalid, it should be[]int{index, restIndex}
The revised version is:
// language: go func twoSum(nums []int, target int) []int { // key is number, value is index numMap := make(map[int]int) for index, num := range nums { rest := target - num if restIndex, ok := numMap[rest]; ok { return []int{index, restIndex} } numMap[num] = index } return []int{} }
I will dive deeper in the next blog, including the error handler and Go routine. See you :D
Related blogs

Reducing ActiveRecord Queries to Speed Up Your Requests
In Rails, ActiveRecord is one of the things that makes the framework so enjoyable to use. It reads almost like natural language and lets you write database logic in a clean, Ruby-style way.But every line of Active Record still turns into real SQL beh...
Software Engineer
Software Engineer



Speed Up Independent Queries Using Rails load_async
When you're building a dashboard, it's common to fetch multiple, independent datasets. The page loading might be slow because it has to fetch all data to render a page. A common solution is using AJAX to load pieces of the dashboard, which is great, ...
Software Engineer
Software Engineer
