No history yet

Go Syntax Basics

Getting Started with Go

Go's syntax is designed to be simple, clean, and highly readable. If you're coming from a language like Python, you'll notice a few key differences right away. Go is statically typed, which means you have to be explicit about the types of your variables. This might seem like extra work at first, but it catches a lot of bugs before your code ever runs.

The basic structure of a Go program is also straightforward. Every executable program must have a main package and a main function, which is the entry point for execution.

package main

import "fmt"

// This is the main function where the program starts.
func main() {
    fmt.Println("Hello, Go!")
}

Variables and Types

In Go, you declare a variable's type when you create it. This is a fundamental shift from dynamically typed languages like Python. The most explicit way to declare a variable is using the var keyword, followed by the variable name and its type.

// Declare a variable named 'score' of type 'int'.
var score int

// Assign a value to it.
score = 100

You can also declare and initialize a variable in one go. If you provide an initial value, Go can often figure out the type on its own. This is called type inference.

// Explicitly typed
var name string = "Alice"

// Type inferred by Go (knows "Alice" is a string)
var city = "New York"

Inside functions, there's an even shorter way to declare and initialize variables: the := operator. This is the most common method you'll see in Go code. It automatically infers the type and assigns the value.

The := syntax is only available inside functions, not for package-level variable declarations.

package main

import "fmt"

func main() {
	// Use := for concise variable declaration and initialization.
	greeting := "Welcome to the tour!"
	age := 35
	pi := 3.14159

	fmt.Println(greeting)
	fmt.Println("Age:", age)
	fmt.Println("Pi:", pi)
}

Go has several built-in types, including int for integers, float64 for floating-point numbers, string for text, and bool for true/false values. Once a variable is declared with a type, you can't assign a value of a different type to it.

Controlling the Flow

Go provides the usual control structures like if, for, and switch, but with some clean, idiomatic touches.

Lesson image

An if statement in Go doesn't require parentheses around the condition. You can also include a short initialization statement that's scoped just to the if-else block.

score := 88

if score >= 90 {
	fmt.Println("Grade A")
} else if score >= 80 {
	fmt.Println("Grade B")
} else {
	fmt.Println("Grade C or lower")
}

Go has only one looping construct: the for loop. It's versatile enough to replace while and do-while loops found in other languages. It has three components separated by semicolons: the init statement, the condition expression, and the post statement.

// A classic for loop
for i := 0; i < 5; i++ {
	fmt.Println(i)
}

// A 'while' loop equivalent
n := 0
for n < 5 {
	fmt.Println(n)
	n++
}

The switch statement is a powerful way to write conditional logic that's cleaner than a long chain of if-else statements. Unlike in many languages, case statements in Go break automatically, so you don't need to add a break at the end of each one.

day := "Tuesday"

switch day {
case "Monday":
	fmt.Println("Start of the work week.")
case "Tuesday", "Wednesday", "Thursday":
	fmt.Println("Midweek.")
case "Friday":
	fmt.Println("Almost there!")
default:
	fmt.Println("Weekend!")
}

Functions and Errors

Functions in Go are declared with the func keyword. You must specify the type for each parameter and the type of the return value.

A standout feature of Go is its ability to return multiple values from a single function. This is the idiomatic way to handle errors.

By convention, functions that can fail return two values: the result and an error. If the error is nil, the operation succeeded. If it's not nil, something went wrong.

Let's look at a function that tries to divide two numbers. Division by zero is an error, so our function needs a way to signal that.

package main

import (
	"errors"
	"fmt"
)

// divide returns a float64 and an error.
func divide(a, b float64) (float64, error) {
	if b == 0 {
		// Return 0 for the float and a new error.
		return 0, errors.New("cannot divide by zero")
	}
	// Return the result and 'nil' for the error.
	return a / b, nil
}

func main() {
	result, err := divide(10.0, 2.0)
	if err != nil {
		// Handle the error.
		fmt.Println("Error:", err)
	} else {
		// Use the result.
		fmt.Println("Result:", result)
	}

	result, err = divide(10.0, 0.0)
	if err != nil {
		fmt.Println("Error:", err)
	} else {
		fmt.Println("Result:", result)
	}
}

This pattern of checking for err != nil is fundamental to writing robust Go code. It makes error handling an explicit and visible part of your program's flow, rather than an afterthought.

Quiz Questions 1/6

True or False: Go is a statically typed language, which means a variable's type is checked at compile-time and cannot change.

Quiz Questions 2/6

What is the entry point for an executable Go program?

This covers the core syntax you'll need to start writing Go. With these building blocks, you can create clear, efficient, and reliable programs.