Image by Author | Ideogram
Â
If you’ve been working with Python and want to add Go to your programming toolbox, you’re in the right place. This article will help you learn the fundamentals of programming with Go.
Rather than starting from zero, we’ll build on what you already know as a Python developer to help you get comfortable with Go’s syntax and concepts. Let’s get started.
🔗 Link to the code on GitHub
Â
Getting Started with Go: Setup & Your First Project
Â
Before writing our first lines of Go code, let’s get our environment set up. Installing Go and creating a project is relatively straightforward compared to Python’s various environment management tools.
To install Go, you can follow these steps:
- First, go to golang.org/dl/
- Download the installer for your operating system (Windows, macOS, or Linux)
- Run the installer, follow the installation steps
- Verify your installation. Run
go version
at your terminal
Â
Note: If you’re interested in only running the code snippets in this tutorial, then use Go playground.
Â
Let’s create a simple project to get you started. Go doesn’t require virtual environments like Python. Instead, it uses a single installation and manages dependencies at the project level.
Create a directory for your project:
$ mkdir hello-go
$ cd hello-go
Â
Initialize a Go module:
Â
This creates a go.mod file, which is similar to Python’s requirements.txt or pyproject.toml but simpler. The command argument (hello) becomes your module name.
Create a file named main.go:
package main
import "fmt"
func main()
fmt.Println("Hello, Go world!")
Â
Run your program:
Â
You should see the following output in your terminal:
Â
Note: All programs in Go are made of packages and they typically start running from the main package. To focus on the concepts better, I’ll show only the relevant lines. But you can place those lines of code in a generic .go file like this:
package main
import "fmt"
func main()
//YOUR CODE GOES HERE
Â
1. Basic Syntax and Variables
Â
Let’s start with the basic structure of a Go program:
Every Go file starts with a package declaration. The main
package is special – it’s the entry point for executable programs. The import
statement brings in packages you need, like fmt
for formatting and printing.
Now let’s look at variable declarations:
// Explicit variable declaration with type
var name string = "Gopher"
Â
In this example, we’re explicitly declaring a variable of type string
. Unlike Python, Go requires you to specify types for your variables.
But you can also use the following syntax that can infer the type:
// Type inference with the := operator
age := 5
Â
The :=
operator both declares and initializes a variable, letting Go figure out the type from the value.
Constants work similarly but use the const
keyword:
// Constant declaration
const pi = 3.14159
Â
In a sample variables.go file, you’ll now have:
package main
import "fmt"
func main()
// Explicit variable declaration with type
var name string = "Gopher"
// Type inference with the := operator
age := 5
// Constant declaration
const pi = 3.14159
fmt.Println(name)
fmt.Println(age)
fmt.Println(pi)
Â
You cannot declare a variable without using it, so we just print out the values of variables here.
Go is statically typed, which is quite different from Python’s dynamic typing. This means all types are checked at compile time, helping catch errors before your program runs.
Â
2. Control Structures
Â
Let’s look at Go’s if statements:
// If statement
score := 85
if score >= 90
fmt.Println("A grade")
else if score >= 80
fmt.Println("B grade")
else
fmt.Println("Lower grade")
Â
Output:
Â
Notice there are no parentheses around the condition, but curly braces are mandatory. Remember, the condition should be a boolean expression.
Now let’s examine Go’s standard for loop:
Â
This loop initializes n
to 0, continues while n < 4
, and increments n
after each iteration.
Count: 0
Count: 1
Count: 2
Count: 3
Â
Go doesn’t have a separate while loop – instead, you use for with just a condition:
// For as a while loop
sum := 1
for sum
Â
To iterate over elements in a collection, use the range
keyword:
// Iterating with range
fruits := []string"apple", "banana", "cherry"
for index, fruit := range fruits
fmt.Println(index, fruit)
Â
This outputs:
0 apple
1 banana
2 cherry
Â
The range
function gives both the index and value (similar to Python’s enumerate()
). If you need only the value, you can use the blank identifier _
:
// Using _ to ignore the index
for _, fruit := range fruits
fmt.Println(fruit)
Â
3. Functions
Â
In Go, you can declare functions with the func
keyword like so:
func add(x int, y int) int
return x + y
Â
You should define the functions outside func main()
and you can call the declared functions inside the main()
function.
Notice that the parameter types come after the parameter names. You specify the return type after the parameter list. When parameters share the same type, you can use a shorthand:
func subtract(x, y int) int
return x - y
Â
One of Go’s distinctive features is the ability to return multiple values:
// Function returning multiple values
func divide(x, y float64) (float64, string)
if y == 0
return 0, "division by zero"
return x / y, ""
Â
You can now call this function:
package main
import "fmt"
...
func main()
result, message := divide(10, 2)
if message != ""
fmt.Println("Error:", message)
else
fmt.Println("Result:", result)
Â
Output:
Â
In addition, Go allows for named return values:
func calculateStats(values []int) (min, max, sum int)
if len(values) == 0
return 0, 0, 0
min = values[0]
max = values[0]
sum = 0
for _, v := range values
if v max
max = v
sum += v
return // naked return
Â
You can call the function with suitable arguments as shown:
package main
import "fmt"
...
func main()
values := []int5, 8, 2, 10, 3
min, max, sum := calculateStats(values)
fmt.Println("Min:", min)
fmt.Println("Max:", max)
fmt.Println("Sum:", sum)
Â
Output:
Â
4. Error Handling
Â
Go’s approach to error handling is different from Python’s exceptions. Instead of try/except blocks, Go functions return errors that must be explicitly checked:
// Importing the errors package
import "errors"
// Function that returns an error
func divide(a, b int) (int, error)
if b == 0
return 0, errors.New("division by zero")
return a / b, nil
Â
When calling a function that might return an error, you check if the error is non-nil:
package main
import (
"errors"
"fmt"
)
// Importing the errors package
// Function that returns an error
func divide(a, b int) (int, error)
if b == 0
return 0, errors.New("division by zero")
return a / b, nil
func main()
// Handling the error
result, err := divide(10, 0)
if err != nil
fmt.Println("Error occurred:", err)
else
fmt.Println("Result:", result)
Â
This raises the error as expected:
Error occurred: division by zero
Â
The focus on explicit error checking helps make Go code robust and readable. It forces you to think about what should happen when something goes wrong.
Â
5. Data Structures
Â
Arrays
Arrays in Go have a fixed size:
// Declaring an array and initializing it
var colors [3]string
colors[0] = "Red"
colors[1] = "Green"
colors[2] = "Blue"
Â
In Go, you can also declare and initialize an array like so:
// Array literal
numbers := [5]int1, 2, 3, 4, 5
Â
Slices
Slices are like Python lists – they’re dynamic arrays:
// Creating a slice
fruits := []string"Apple", "Banana", "Cherry"
Â
You can add elements to a slice using append like so:
// Adding elements to a slice
fruits = append(fruits, "Date")
Â
Note that append returns a new slice – it doesn’t modify the slice in place.
You can also create slices from other slices or arrays.
Â
Maps
Maps are Go’s equivalent to Python dictionaries:
// Creating a map
ages := map[string]int
"Alice": 25,
"Bob": 30,
Â
Accessing, adding, and updating values works as you’d expect:
// Working with maps
fmt.Println(ages["Alice"]) // 25
ages["Charlie"] = 22 // Add a new entry
ages["Alice"] = 26 // Update an existing entry
Â
Checking if a key exists is a common operation:
// Check if a key exists
age, exists := ages["Dave"]
if exists
fmt.Println("Dave's age:", age)
else
fmt.Println("Dave not in map")
Â
Output:
Â
To remove a key-value pair, use:
// Delete an entry
delete(ages, "Bob")
Â
6. Concurrency with Goroutines and Channels
Â
The Go runtime manages lightweight threads called Goroutines:
// Starting a goroutine
go func()
fmt.Println("Running in a goroutine")
()
Â
The go keyword starts a new goroutine. Here we’re using an anonymous function, but you can also run named functions in goroutines.
Channels are used for communication between goroutines:
// Creating a channel
ch := make(chan string)
Â
Send data to a channel:
// Sending to a channel
go func() {
ch
Â
Receive data from a channel:
Â
Here’s a more complete example that shows the usefulness of this approach:
ch := make(chan string)
// Goroutine that produces values
go func() {
for i := 0; i
Â
The range loop will continue until the channel is closed, making it easy to process all values sent to the channel.
Received: Message 0
Received: Message 1
Received: Message 2
Received: Message 3
Received: Message 4
Â
Wrapping Up
Â
Go offers a compelling alternative to Python with its strong typing, compilation to native code, and excellent concurrency support. As a Python developer, you’ll find that Go’s emphasis on simplicity and readability makes it relatively easy to pick up, though you may need to adjust to explicit type declarations and a different error handling approach.
Some key takeaways:
- Go is statically typed, compiled, and focuses on simplicity
- Error handling in Go is explicit with returned error values
- Go’s concurrency model with goroutines and channels is powerful and intuitive
- The syntax is minimal compared to Python but expressive in its own way
I hope this introduction helps you get started with Go programming. Happy coding!
Â
Â
Bala Priya C is a developer and technical writer from India. She likes working at the intersection of math, programming, data science, and content creation. Her areas of interest and expertise include DevOps, data science, and natural language processing. She enjoys reading, writing, coding, and coffee! Currently, she’s working on learning and sharing her knowledge with the developer community by authoring tutorials, how-to guides, opinion pieces, and more. Bala also creates engaging resource overviews and coding tutorials.