Go Syntax
Understanding Go's syntax is the first real step toward writing clean, idiomatic Go programs. Go was deliberately designed with a small, consistent grammar, which is part of why it's often recommended as an approachable language even for programmers new to compiled, statically typed languages.
Basic Structure of a Go Program
Every Go source file is built from the same four components, always in this order:
- Package declaration
- Import statements
- Top-level declarations (functions, types, variables, constants)
- Statements and expressions inside those declarations
package main
import "fmt"
func main() {
fmt.Println("Learning Go syntax step by step")
}
1. Package Declaration
package main
- Every Go file belongs to exactly one package, declared on the first line.
- The
mainpackage is special: it marks this code as a runnable program rather than a reusable library, and it must contain amain()function. - Program execution always begins inside
main()in themainpackage.
2. Import Statement
import "fmt"
importbrings in code from the standard library or from external modules.fmt(short for "format") provides functions for formatted input and output, such asPrintlnandPrintf.- To import multiple packages, group them in parentheses:
import (
"fmt"
"strings"
)
3. Function Definition
func main() {
// ...
}
funcdeclares a function.main()takes no arguments and returns nothing — it is the fixed entry point Go looks for when running amainpackage.- The code between
{and}is the function body, executed line by line when the function runs.
4. Statements and Expressions
fmt.Println("Learning Go syntax step by step")
- This line is a statement: a complete instruction that performs an action (here, printing to the console).
fmt.Printlnuses dot notation to call thePrintlnfunction that belongs to thefmtpackage.
Statements and Line Endings
Go statements are normally written one per line:
fmt.Println("Line 1")
fmt.Println("Line 2")
Behind the scenes, the Go compiler automatically inserts a semicolon at the end of most lines, following a fixed set of rules (for example, after an identifier, a closing bracket, or a literal value). This is why Go code rarely needs explicit semicolons — you're allowed to write them, but idiomatic Go style always omits them, and the standard formatter (gofmt) removes them automatically.
The Curly Brace Rule
Because the compiler inserts semicolons based on what's at the end of a line, Go enforces a strict rule: the opening brace { of a block must be on the same line as the statement that introduces it. This isn't just a style preference — it will not compile otherwise.
Incorrect — causes a compilation error:
func main()
{
fmt.Println("Invalid formatting")
}
The automatic semicolon insertion places a semicolon right after func main(), which the compiler reads as an empty function declaration followed by a stray, disconnected block — a syntax error.
Correct:
func main() {
fmt.Println("Proper formatting")
}
Example: Multiple Statements
package main
import "fmt"
func main() {
x := 5
y := 3
sum := x + y
fmt.Println("Sum:", sum)
}
Expected output:
Sum: 8
Writing Compact Code (Not Recommended)
Go's grammar technically allows multiple statements on one line, separated by explicit semicolons:
package main; import "fmt"; func main() { fmt.Println("Compact but hard to read") }
This compiles, but you should avoid writing code this way.
Why avoid it:
- It is harder to read, scan, and debug.
- It goes against Go's own formatting convention, enforced by the
gofmttool that ships with the language. - Nearly every Go codebase — including the standard library itself — is formatted with one statement per line, so compact code stands out as non-idiomatic and will typically be rewritten by
gofmtthe moment someone runs it.
Tip: Run gofmt -l . in a project directory to list any files that don't match Go's standard formatting, or gofmt -w . to reformat them automatically. Most editors run this on every save once the Go extension is installed.