Syntax and Comments

Go's syntax is small on purpose. This lesson covers the rules every Go file follows: how a file is laid out, statements and automatic semicolons, blocks and braces, identifiers and keywords, and the two kinds of comments — including doc comments, which become your package's documentation.

The shape of a Go file

Every file has the same three parts, in this order: the package clause, the imports, and then declarations of functions, types, variables and constants in any order.

GO
package main // 1. which package this file belongs to

import ( // 2. packages this file uses
	"fmt"
	"math"
)

// 3. declarations, in any order
const radius = 2.5

func area(r float64) float64 {
	return math.Pi * r * r
}

func main() {
	fmt.Printf("A circle of radius %.1f has area %.2f\n", radius, area(radius))
}
Output
A circle of radius 2.5 has area 19.63

main calls area, which is declared above it, but the order doesn't matter: a package-level name can be used anywhere in the package. The grouped import ( … ) form is the usual way to import several packages; gofmt sorts them alphabetically.

Statements and semicolons

Go's grammar uses semicolons, but you almost never type them. The compiler adds one automatically at the end of a line that ends with an identifier, a literal, ), ], }, or keywords such as return and break. Two consequences:

  • An opening brace must be on the same line as its func, if, for or switch (lesson 3 showed the error).
  • When you split a long expression or argument list over several lines, end each line with an operator or a comma, so no semicolon is inserted.
GO
package main

import "fmt"

func main() {
	total := 1 +
		2 +
		3
	fmt.Println(
		"total:",
		total, // the trailing comma is required here
	)
	a, b := 1, 2; fmt.Println(a + b) // two statements on one line: legal, but gofmt would split them
}
Output
total: 6
3

(That last line is only there to show the rule. gofmt would put each statement on its own line, and so should you.)

Blocks and braces

Curly braces group statements into a block. Braces are always required — even for a one-line if — and the condition of an if or for has no parentheses:

GO
package main

import "fmt"

func main() {
	temperature := 31
	if temperature > 30 {
		fmt.Println("It's hot")
	}
	for i := 1; i <= 3; i++ {
		fmt.Println("lap", i)
	}
}
Output
It's hot
lap 1
lap 2
lap 3

Identifiers

Names of variables, functions, types and packages start with a letter or underscore, followed by letters, digits or underscores. They are case-sensitive, and the case of the first letter matters:

StyleExampleMeaning
Starts with a capitalPrintln, MaxSizeExported: usable from other packages
Starts with a lowercase letterarea, userCountUnexported: private to its package

Go style is mixedCaps: userCount or UserCount, never user_count. Acronyms keep one case throughout, as in userID, ServeHTTP and parseURL. Short names are normal for short-lived variables (i, n, err); longer, more descriptive names suit things used far from where they're declared.

The underscore on its own, _, is the blank identifier. Assigning to it throws a value away, which is how you ignore a result you don't need.

Keywords

Go has just 25 reserved words, and you can't use them as names:

breakcasechanconstcontinue
defaultdeferelsefallthroughfor
funcgogotoifimport
interfacemappackagerangereturn
selectstructswitchtypevar

Names such as int, string, true, nil, len and append are predeclared rather than reserved. You could technically reuse them, but shadowing them only causes confusion — don't.

Comments

GO
package main

import "fmt"

/*
A block comment can span
several lines. It's mostly used to switch off chunks of code.
*/

func main() {
	// A line comment runs to the end of the line.
	fmt.Println("comments are ignored") // it can follow code, too
}
Output
comments are ignored

Most Go code uses // line comments, even for long explanations.

Doc comments

A comment placed directly above a package-level declaration, with no blank line between, is a doc comment. Tools such as go doc, your editor's hover help and pkg.go.dev show it as documentation. By convention it is a full sentence that starts with the name being described:

GO
// Package main prints a short shipping quote.
package main

import "fmt"

// FreeShippingThreshold is the order total above which shipping is free.
const FreeShippingThreshold = 50.0

// ShippingCost returns the delivery charge for an order total.
// Orders at or above FreeShippingThreshold ship for free.
func ShippingCost(total float64) float64 {
	if total >= FreeShippingThreshold {
		return 0
	}
	return 4.99
}

func main() {
	fmt.Println(ShippingCost(32.50), ShippingCost(75))
}
Output
4.99 0

Write a doc comment for everything exported. go vet doesn't insist on it, but readers of your package will be grateful.

Try it yourself

Add a doc comment and a second function, Discount, that returns 10% of a total.

Try it yourself · main.go
Edit the code, copy it into main.go in a new folder and run it with go run main.go (Go 1.27 or later). How to install Go
Output
Shipping: 4.99
Next: declaring variables.