From Zero to Go Hero: Learn Go Programming with Me - Part 2
Understanding Core Concepts

I'm a mobile/web developer 👨💻 who loves to build projects and share valuable tips for programmers
Follow me for Flutter, React/Next.js, and other awesome tech-related stuff 😉
Introduction
Hey there! Welcome to Part 2 of the series of Learning Go with me. In Part 1 we set the stage by introducing the project, defining its goals, and setting up the basic folder structure for our Go project.
Now it’s time to dive deeper into some fundamental concepts of Go programming.
In this part, we’ll cover core topics like how Go organizes code using packages and imports, how exported names work, and explore basic Go constructs such as types, variables, constants, functions, slices, maps, loops, and conditionals. Then we’ll also understand how structs and pointers work.
I will try my best to explain each concept in a beginner-friendly way and in a way that I understand because I am also learning with you. I will try to incorporate these concepts in a way that after understanding it we can directly apply it to our CRUD API project.
By the end of this section, you’ll have a strong grasp of these concepts and be ready to use them to bring our API to life.
Let’s jump right in it without wasting any more time
Packages
What is a Package in Go?
In Go, packages are a way to organize and reuse code. What does that mean?
Think of a Package like a Folder on your computer. Inside that folder, you have related files. Similarly in Go, the files inside a package folder work together to provide some functionality
For example:
- If you are familiar with
mathpackage in any other language then you must know that it contains tons of mathematical operations. So all these operations are inside this math package
- If you are familiar with
And when you want these functions which are defined somewhere else inside your program, you use “import“.
Types of Packages
Standard Library Packages:
- These are built-in packages in Go. Packages like
mathfor mathematical operations,net/httpfor handling HTTP requests,encoding/jsonfor working with JSON, etc.
- These are built-in packages in Go. Packages like
Third-Party Packages:
- These are the additional packages that are created by people in the Go community. If you remember, in Part 1 we installed a few dependencies using
go getthe command. Those belong to this type.
- These are the additional packages that are created by people in the Go community. If you remember, in Part 1 we installed a few dependencies using
Custom Packages:
- You can create your own packages too which you can use to organize code. We will see this in action soon.
How Packages Work?
- In Go, every program belongs to a package. The
mainpackage is special because it’s where the program starts running. When we define the main package inside a file, Go will know from where it should start the program.
Using Packages in Our Project
- In Part 1 we created different folders and files. If you have noticed, every folder and files are in red color which shows that something is wrong. This is because we need to tell which file belongs to which package. Let’s resolve this.

- Go to each file and write the folder name as a package it belongs to.
// cmd/main.go
package main
// config/config.go
package config
// databse/db.go
package database
// internal/books/handler.go, model.go and service.go
package books
// routes/routes.go
package routes
//pkg/logger
package logger
- All the errors should be gone after giving the package name inside every file.
Imports
- To use any package inside a Go project, we need to import it using
importa keyword.
import "fmt"
- If you have multiple packages then list them in parentheses
import (
"fmt" // for printing.
"net/http" // to handle HTTP requests and responses.
"encoding/json" // to parse and generate JSON data
)
Exported Names
What Are Exported Names?
So in Go, we don’t have keywords like
privateorpubliclike other languages.If the name starts with an uppercase letter, then it is considered as exported, meaning it can be accessed from outside the package where they’re defined.
Names starting with a lowercase letter are unexpected and private to the package.
Example
type Book struct { // Exported struct
Title string // Exported field
Author string // Exported field
}
type car struct { // Unexported struct
brand string // Unexported field
isElectric bool // Unexported field
}
Above we created two structs (don’t worry if you don’t know about structs. We will see it in detail in this blog below).
Here
Bookstarts with an uppercase letter, meaning we can get this struct in other packages whereascarstarts with a lowercase letter, meaning we can’t access this struct anywhere else.
Basic Go Concepts
Types and Variables
Go is a statically typed language. This means every variable must have a type that’s known at compile time. Common types include:
int: Integer valuesstring: Text databool: Boolean values (true/false)float: Decimal values
Declaring Variables
- There are two ways you can declare a variable:
- Explicit Declaration
var age int = 24
var name string = "Dhruv"
- Implicit Declaration
age := 24
name := "Dhruv"
- You can also declare with no value like this:
var age int // Defaut: 0
var name string // Default: ""
Constants
Constants are immutable values, which means we can’t change them once defined.
Use
constkeyword to declare constantsWhy Use Constants?
We use it to prevent accidental changes to critical values.
To improve the readability and maintainability of code
const apiVersion = "v1"
const defaultPort = 8080
- You can use parentheses for multiple declarations too
const (
apiVersion = "v1"
defaultPort = 8080
)
Functions
- We use
funckeyword to declare functions in Go.
func functionName(){
// logic
}
- You can have parameters inside parentheses
func functionName(parameter1 type, parameter2 type){
// logic
}
- You can return from a function by defining a return type like this
// Single value return
func functionName() int {
return 0
}
// For multiple value return
func functionName() int, string {
return 0, "Hello"
}
Conditionals
- The
ifstatement is used for decision-making
marks := 85
if marks >= 9- {
fmt.Println("Grade: A")
} else if marks >= 75 {
fmt.Println("Grade: B")
} else {
fmt.Println("Grade: F")
}
- Short Statement with
if. In this, we are first declaringnum, and right after that we are checking the condition for it.
if num := 10; num%2 == 0 {
fmt.Println("The number is even.")
} else {
fmt.Println("The number is odd.")
}
Loops
- In Go we have only
for loopfor looping. There are different ways you can useforloop. Let’s see it in action
// Basic `for` loop
for i:= 0; i<5; i++ {
fmt.Println("Value of i: ,", i)
}
// Infinite Loop
count := 0
for {
fmt.Println("Looping forever")
count++
if count == 3 {
break // Exists the loop
}
}
// Condition Only Loop
count:= 0
for count < 3 {
fmt.Println("Count: ", count)
count++
}
Struct
If you come from programming languages like Javascript, Dart, or Python, you must be familiar with
classandobjects.In Go we don’t have that. We use
structto group data together.Let’s take an example of our CRUD API project. We need to represent a book with multiple details like a
title,id,name, etc.So instead of creating separate variables for each piece of data, you can use a
structto combine all of those into one entity.
Defining a Struct
- To define a structure, you use the
typekeyword followed by the structure name and its field. Each field has a name and a type
type Book struct {
ID string
Title string
Author string
Year int
}
Creating and Using a Struct
- Once we have defined a structure, we can use it to create an object and assign values to its fields
var book1 Book // Creates an instance of `Book` struct
book1.ID = "1" // Assigns the value "1" to the ID field of struct
book1.Title = "Maths"
book1.Author = "Jane"
book1.Year = 2012
Initializing a Struct in Different Ways
Using Field Names
- We can initialize a struct by specifying the field names and their values like below
book1 := Book{
ID: "1"
Title: "Maths"
Author: "Jane"
Year: 2012
}
- This looks clear, isn’t it?
Without Field Names
- We can initialize it without field names too like this
book1 := Book{
"1"
"Maths"
"Jane"
2012
}
- This is less readable because it relies on the order of fields.
Structs with Methods
A method is a function that is attached to a specific type. This type of method initialization was new and kinda weird for me at first. Because usually we are required to create methods inside a class in other languages right? but here we create it separately and then attach it to the structure using the receiver.
Let me show you how
type Book struct {
ID string
Title string
Author string
Year int
}
func (b Book) SayBookName() {
fmt.Println("This book name is: ", b.Title)
}
func main() {
book1 := Book{
ID: "1"
Title: "Maths"
Author: "Jane"
Year: 2012
}
book1.SayBookName() // Call the SayBookName method
}
As you can see to attach this
SayBookNamemethod toBookstruct we provided receiver before the method name inside the parenthesis(b Book). So Inside this file wherever any method has this receiver it will automatically get attached to this struct.You can also nest struct inside a struct like this
type Book struct {
ID string
Title string
Author Author // Nested struct
Year int
}
type Author struct {
FirstName string
LastName string
}
func main() {
book1 := Book{
ID: "1"
Title: "Maths"
Author: Author{
FirstName: "Jane"
LastName: "Doe"
}
Year: 2012
}
}
Slice
A slice in Go is a data structure used to hold a collection of elements of the same type.
Think of it as a more powerful and flexible version of an array.
While arrays have fixed sizes, slices can grow and shrink dynamically.
It’s really simple to use
Creating Slices
Using the
makefunction- The
makefunction creates a slice with a specific length and capacity.
- The
slice := make([]int, 3, 5) // Create a slice of type int, of length 3 and capacity 5
Here length represents the number of elements currently in the slice which is 3 here: [0,0,0]
And Capacity represents the total space allocated for the slice which is (5). This means this slice can have max 5 elements in it.
Using a Slice Literal
- We can define a slice directly with values using slice literal
slice := []int{1,2,3,4,5}
Adding Elements to a Slice
- We can add elements to a any slice using
appendfunction.
slice := []int{1,2,3}
slice = append(slice, 4,5) // adding 4 and 5 to the slice
- We need to pass the slice where we want to add elements as the first parameter and then we can pass as many elements as we want after that.
Iterating Over a Slice
- We use
forloop to access elements in a slice
slice := []int[1,2,3,4,5]
for index, value := range slice {
fmt.Println("Index: ", index, "Value: ",value)
}
for _, value := range slice {
fmt.Println("Value: ",value)
}
Range
Here
rangethe keyword is used to iterate over elements in a variety of data structures. In the above example, we userangeto print the index and value in a slice.We use underscore (
_) to skip the variable if it’s not needed
Slicing a Slice
- We can create a new slice by slicing an existing one.
slice := []int{1,2,3,4,5}
newSlice := slice[1:3] // Slice from index 1 to 2 (3 is exclusive)
// newSlice: [2,3]
Length And Capacity
- Slices have both length and capacity as we saw above. To get the length and capacity of a slice we use
len()andcap()functions
slice := []int{1,2,3,4,5}
fmt.Println("Length: ", len(slice)) // 5
fmt.Println("Capacity: ", cap(slice)) // 5
Appending Slices
We can add a whole new slice to an existing slice using
. . .(unpack operator)slice := []int{1,2,3,4,5} slice2 := []int {6,7,8} combined := append(slice, slice2...) // [1,2,3,4,5,6,7,8]
Map
This is another very helpful data structure in Go which is built in inside it. It stores
key,value. This is similar to dictionaries in Python or hash maps in other programming languages.Keys must be of a comparable type that is
string,intand values can be of any type.This data structure is useful, especially for lookups when the key uniquely identifies the data. In our case, it is Book ID
Declaring and Initializing a Map
- Using
make
myMap := make(map[string]int)
myMap["Maths"] = 2
myMap["Biology"] = 3
- Here [string] represents
keyand int representsvalue
Using Map Literal
- We can initialize and create a map in a single step like we did in struct
myMap := map[string]int{
"Math": 2,
"Biology": 3,
}
Accessing Values in a Map
- To get the value associated with a key, you have to use the map followed by the key in square brackets
myMap := map[string]int{
"Math": 2,
"Biology": 3,
}
fmt.Println(myMap["Maths"]) // 2
Checking if a Key Exists
- We use the comma ok idiom to check if a key exists or not. This is very useful when we need to check if certain keys exist in a map or not. We can do that in a single line of code
myMap := map[string]int{
"Math": 2,
"Biology": 3,
}
value, ok := myMap["Physics"]
if exists {
fmt.Println("Value: ", value)
} else {
fmt.Println("Key does not exist")
}
value, exists := myMap["Physics"]: ok istrueif the key is present andfalseotherwise.
Adding and Updating Elements
- It’s really easy, you just access the value using the key and add a new value or assign a different value to it
myMap := map[string]int{
"Math": 2,
"Biology": 3,
}
myMap["Physics"] = 4 // Adding new element
myMap["Math"] = 1 // Updating exisitng element
Deleting Elements
- We use
delete()function to remove a key-value pair from the map
myMap := map[string]int{
"Math": 2,
"Biology": 3,
}
delete(myMap, "Math") // Remove the key "Math"
Iterating Over a Map
- We use again
forloop withrangeto iterate over all key-value pairs.
myMap := map[string]int{
"Math": 2,
"Biology": 3,
}
for key, value:= range myMap {
fmt.Println("Key: ", key, "Value: ", value)
}
Wrapping Up
I think that’s pretty much all you need to know for now. We learned lots of fundamental stuff in this article. I tried to make it as concise as possible in order to quickly grasp the underlying concepts because going into too much detail with all the theory doesn’t make sense at this point.
There is still one concept remaining which is Pointers. I wanted to cover it in this blog only but then thought it would become quite a big read so I will be explaining it in detail in the next blog.
I hope after this article you are at least comfortable with the basic stuff and syntaxes. Just practice the syntax that you find difficult to grasp. It will all make sense and your hands will then flow naturally on the keyboard afterwards.
See you in the next one, until then…






