Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Go  Module 1 – Getting started with Go 1.27

Your first Go program: go run and go build

Write a Go program, run it with go run, build a binary with go build, read its build information and fix the first compile errors beginners meet.

  • Beginner
  • 15 minutes
  • Examples run with Go 1.27.1 and Python 3.14.8
  • By MySmartCoPilot
Free lesson, Pro answers: 15 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Write a main package and run it with go run
  • Fix the first compile errors: an unused import, an unused variable and a brace on its own line
  • Format a file with gofmt and find a suspicious call with go vet
  • Build a binary with go build, read its build information and build it for another system

Before you start

What you’ll learn · Before you start

What you will learn

  • Write a main package and run it with go run
  • Fix the first compile errors: an unused import, an unused variable and a brace on its own line
  • Format a file with gofmt and find a suspicious call with go vet
  • Build a binary with go build, read its build information and build it for another system

Before you start

On this page

A Go program of ten lines, built with one command, becomes a 2.3 MB file that runs on its own, and the same command builds it for Linux and Windows from a Mac. On the way you meet the three errors every newcomer sees first: an unused import, an unused variable and an opening brace on a line of its own.

You will write and run a main package, fix those three errors, let gofmt lay out the code and go vet check it, build an executable and read the build information it carries, and build the same program for two other systems.

A program starts in func main of package main

Every Go file begins with a package clause, and a program is the package named main. Here is a whole program:

hello.go: a whole program Go · hello.go
// hello.go: a whole Go program. It starts in func main of package main.
package main

import "fmt"

func main() {
	name := "Asha"
	fmt.Println("Hello,", name)
	fmt.Printf("%s has %d letters\n", name, len(name))
}

Output

Hello, Asha
Asha has 4 letters

Recorded with Go 1.27.1 on macOS 26 arm64. To run it yourself: go run hello.go

Read it from the top. package main says this file belongs to the package main: The package that makes a program. It must be named main and declare a func main that takes no arguments and returns nothing; running the program runs that function.. import "fmt" makes the standard formatting package available under the name fmt. func main() is where the program starts: the specification says a program runs by initializing it and then calling the function main of package main, which takes no arguments and returns no value, and the program ends when main returns. Inside it, name := "Asha" declares a variable and gives it a value at once, fmt.Println prints its arguments separated by spaces, and fmt.Printf fills %s with a string and %d with a whole number.

go run hello.go compiled that file and ran it; its output is under the code. Step through what the command did, and what changes when you run the same, unchanged file a second time:

Interactive · stage by stage What go run hello.go does Step through the first run of hello.go, then a second run of the same, unchanged file.
What go run hello.go does, step 6 of 6. Showing go run hello.go, Compile package main, Link an executable, Keep a copy, Run it (started the cached copy). In focus: Run it, again.unchanged: start the copygo run hello.gobuild it, then run itCompile package mainfmt comes from the cacheLink an executablein a temporary folderKeep a copyin the build cacheRun itstarted the cached copy

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. The command. go run takes a main package, here the single file hello.go, builds it and runs the result. Arguments after the file name are passed on to the program.
  2. Compile. The compiler turns hello.go into machine code. Packages it imports, such as fmt, are compiled once and then taken from the build cache. By default go run leaves out the information a debugger uses, to save time.
  3. Link. The linker joins that code with the compiled packages and the Go runtime into one executable, written into a temporary folder that the go command removes when it is done.
  4. Keep a copy. Since Go 1.24 the executable is also kept in the build cache. Repeated runs get faster, at the cost of a larger cache.
  5. Run. The go command starts the executable, which prints Hello, Asha and Asha has 4 letters. The exit status of go run itself is not the exit status of the program.
  6. A second run. Run the same, unchanged file again and the go command finds the executable in the build cache and starts it at once, with no compile and no link.

go run is the command for writing and trying a program: it leaves no file beside your code. The program it built lives in a temporary folder while it runs, and a copy waits in the build cache for the next run.

Checkpoint

Check: A main package, run with go run

  1. Question 1 of 2 Where does a Go program start running?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: In func main of package main, once the program is initialized

    A program is the package main, which must declare a func main that takes no arguments and returns nothing. The program ends when that function returns.

  2. Question 2 of 2 You run go run hello.go twice without changing the file. What does the second run leave out?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Compiling and linking, because it starts the copy kept in the build cache

    go run compiles, links into a temporary folder, keeps a copy in the build cache and runs it. With the same file, the next go run finds that copy and starts it directly.

Go refuses an unused import or an unused variable

Programs change while you write them, and a line you no longer need is easy to leave behind. Go does not let it stay. This file imports a package it never uses and declares a variable it never reads:

unused.go: an import and a variable nobody uses Go · unused.go
// unused.go: an import and a variable that are never used.
package main

import (
	"fmt"
	"os"
)

func main() {
	count := 3
	fmt.Println("Hello, Go")
}

Output (exit status 1)

Printed as an error (standard error)

# command-line-arguments
./unused.go:6:2: "os" imported and not used
./unused.go:10:2: declared and not used: count

Recorded with Go 1.27.1 on macOS 26 arm64. To run it yourself: go run unused.go

The run failed before anything was built, with two errors: "os" imported and not used and declared and not used: count. The first comes from the specification itself, which makes it illegal to import a package without referring to anything it exports. The second is an implementation restriction: the specification allows a compiler to reject a variable declared inside a function body and never used, and the standard compiler does. An unused function, or an unused variable at package level, outside every function, compiles; only these two cases stop the build.

What the file contains What the compiler does
An import whose package the file never uses Stops: illegal in the specification
A local variable that is set and never used Stops: the compiler’s restriction
A local variable you assign to _ Compiles: the value is thrown away on purpose
An unused function or package-level variable Compiles

The blank identifier: The name _ (an underscore), which takes a value and throws it away. It lets code ignore a result on purpose, or import a package only for what it does when it starts. _ is the deliberate way out. _ = count uses the value by throwing it away, and import _ "image/png" imports a package only for what it does when the program starts.

Silencing the error and keeping the line

_ = count makes the error go away, and it also hides the mistake the error found. Use it for a moment while a change is half done, then delete both lines, or use the variable. For imports, let your editor organise them: gopls can add and remove imports for you, usually when you save.

A line break can end a statement, so the brace stays on the line

Go source has no semicolons at the ends of lines, because the compiler inserts them. That rule, called semicolon insertion: Go's rule that a semicolon is added after a line whose last token could end a statement, such as a name, a literal or a closing bracket. It is why an opening brace must stay on the line before it., decides where an opening brace may go:

brace.go: the brace on a line of its own Go · brace.go
// brace.go: the opening brace on a line of its own.
package main

import "fmt"

func main()
{
	fmt.Println("Hello, Go")
}

Output (exit status 1)

Printed as an error (standard error)

# command-line-arguments
./brace.go:7:1: syntax error: unexpected semicolon or newline before {

Recorded with Go 1.27.1 on macOS 26 arm64. To run it yourself: go run brace.go

The compiler stopped at line 7, column 1: syntax error: unexpected semicolon or newline before {. Step through what it did with the two lines:

Interactive · stage by stage Why a brace on its own line is a syntax error Step through what the compiler does with lines 6 and 7 of brace.go.
Why a brace on its own line is a syntax error, step 4 of 4. Showing Line 6: func main(), A semicolon is added, Line 7: {, A syntax error (fixed: brace on line 6). In focus: A syntax error.Line 6: func main()its last token is )A semicolon is addedas if: func main();Line 7: {a block with no functionA syntax errorfixed: brace on line 6

The drawing shows the whole scene; its 4 steps are listed below.

Every step as text
  1. The line ends. Go source has no semicolons at the ends of lines because the compiler adds them. The specification's rule adds one after a line whose last token is a name, a literal, a few keywords such as return, ++ or --, or a closing ), ] or }.
  2. A semicolon goes in. Line 6 ends with ), so a semicolon is added after it. The compiler now reads func main(); as a complete declaration of a function without a body.
  3. The brace alone. Line 7 starts with an opening brace. At this point the compiler expects a new declaration, and a block cannot start one.
  4. The error. The compiler stops with syntax error, unexpected semicolon or newline before {, at line 7, column 1. Move the brace to the end of line 6, where gofmt puts it, and the file compiles.

The same rule holds for if, for, switch and select: Effective Go notes that the opening brace of a control structure cannot go on the next line, because a semicolon would be inserted before it. So there is no brace style to choose in Go, and the tool of the next section puts every brace where it belongs anyway. The rule is also why most Go lines have no semicolon at all: you write them only between the clauses of a for loop, as in for i := 0; i < 3; i++, or to put two statements on one line.

Checkpoint

Check: Unused imports and variables · Semicolons and where braces go

  1. Question 1 of 2 What happens when you run this file with go run?

    Read the code, then choose one answer.

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func main() {
        total := 0
        fmt.Println("done")
    }
    Show the answer: Question 1 of 2

    Answer: It does not compile, because strings is imported and not used, and total is declared and not used

    An import must be used, and a local variable must be read. Remove both lines, or use them, and the file compiles.

  2. Question 2 of 2 Why does this part of a function not compile?

    Read the code, then choose one answer.

    if len(name) > 3
    {
        fmt.Println(name)
    }
    Show the answer: Question 2 of 2

    Answer: The line ends with the literal 3, so a semicolon is inserted there and the if has no block

    The semicolon rule adds a semicolon after a line whose last token could end a statement, such as a name, a literal or a closing bracket. The compiler then expects the block on the same line as the if, and stops at the end of that line.

gofmt lays the code out, and go vet finds what compiles but is wrong

Go has one layout for source code, and a tool applies it. gofmt: The tool that lays out Go source in the one standard format, with tabs for indentation and spaces for alignment. gofmt -l lists the files it would change and gofmt -w rewrites them. indents with tabs, aligns with spaces, and puts every space and blank line where the standard format wants it, so layout never has to be discussed in a code review; go fmt ./... runs it on every package of a module. Here are two files: the first typed without care, the second laid out well but with a bug:

tidy/messy.go, as typed Go · tidy/messy.go
package main
import "fmt"
func main() {
    name:="Asha"
  if len(name)>3 {
        fmt.Println("Hello,",name)
  }
}
tidy/vetme.go: it compiles Go · tidy/vetme.go
// vetme.go: it compiles, but the verb %d does not fit a string.
package main

import "fmt"

func main() {
	name := "Asha"
	fmt.Printf("Hello, %d\n", name)
}
gofmt and go vet on the two files Python · format_session.py
from session import run

# gofmt lists, shows and fixes layout; go vet finds a bug the compiler accepts.
run(
    """
gofmt -l tidy
gofmt -d tidy/messy.go
gofmt -w tidy/messy.go
gofmt -l tidy
go vet tidy/vetme.go
go run tidy/vetme.go
""",
    expect_failure=["gofmt -d tidy/messy.go", "go vet tidy/vetme.go"],
)

Output

$ gofmt -l tidy
tidy/messy.go
$ gofmt -d tidy/messy.go
diff tidy/messy.go.orig tidy/messy.go
--- tidy/messy.go.orig
+++ tidy/messy.go
@@ -1,8 +1,10 @@
 package main
+
 import "fmt"
+
 func main() {
-    name:="Asha"
-  if len(name)>3 {
-        fmt.Println("Hello,",name)
-  }
+	name := "Asha"
+	if len(name) > 3 {
+		fmt.Println("Hello,", name)
+	}
 }
[exit status 1]
$ gofmt -w tidy/messy.go
$ gofmt -l tidy
$ go vet tidy/vetme.go
tidy/vetme.go:8:21: fmt.Printf format %d has arg name of wrong type string
[exit status 1]
$ go run tidy/vetme.go
Hello, %!d(string=Asha)

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 format_session.py

Command What it does In the session
gofmt -l Lists the files whose layout differs tidy/messy.go
gofmt -d Shows the changes as a diff blank lines added, tabs and spaces fixed
gofmt -w Rewrites the files afterwards -l lists nothing
go vet Reports code that is probably wrong the %d verb with a string

gofmt -d ended with exit status 1 after showing its changes, which lets a script fail on unformatted code. The last two commands show why go vet: The go command that reports code which compiles but is probably wrong, such as a Printf verb that does not fit its argument. matters: vetme.go compiles, and it runs, but it prints Hello, %!d(string=Asha), because %d expects a number and got the string Asha. vet caught the mistake before the program ran: fmt.Printf format %d has arg name of wrong type string. Editors can run gofmt each time you save, and gopls reports static-analysis findings while you type.

Key idea

gofmt decides the layout and go vet looks for code that compiles but is probably wrong; run both before every commit.

Checkpoint

Check: gofmt and go vet

  1. Question 1 of 2 Which command lists the files whose layout differs from the standard format, without changing them?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: gofmt -l

    gofmt -l lists, gofmt -d shows the changes as a diff, and gofmt -w makes them.

  2. Question 2 of 2 A program contains fmt.Printf("%d items\n", "seven"). It compiles. What does go vet report, and what would the program print?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: vet reports that %d has an argument of the wrong type, string, and the program prints %!d(string=seven) items

    fmt reports a wrong verb at run time by printing %!d(string=...). go vet finds the same mistake before the program ever runs.

go build writes one executable that records how it was built

go run keeps nothing beside your code. To get a file you can test, copy or ship, make the program a module and build it. The session makes a module named example.com/greeter from hello.go, builds it, runs the result and looks inside:

From hello.go to an executable Python · build_session.py
from session import run

# Make a module from hello.go, build it, run the binary and read what it carries.
run("""
mkdir greeter
cp hello.go greeter/main.go
cd greeter && go mod init example.com/greeter
cat greeter/go.mod
cd greeter && go build
ls greeter
./greeter/greeter
du -h greeter/greeter
go version -m greeter/greeter
file greeter/greeter
""")

Output

$ mkdir greeter
$ cp hello.go greeter/main.go
$ cd greeter && go mod init example.com/greeter
go: creating new go.mod: module example.com/greeter
go: to add module requirements and sums:
	go mod tidy
$ cat greeter/go.mod
module example.com/greeter

go 1.27.1
$ cd greeter && go build
$ ls greeter
go.mod
greeter
main.go
$ ./greeter/greeter
Hello, Asha
Asha has 4 letters
$ du -h greeter/greeter
2.3M	greeter/greeter
$ go version -m greeter/greeter
greeter/greeter: go1.27.1
	path	example.com/greeter
	mod	example.com/greeter	(devel)	
	build	-buildmode=exe
	build	-compiler=gc
	build	CGO_ENABLED=1
	build	CGO_CFLAGS=
	build	CGO_CPPFLAGS=
	build	CGO_CXXFLAGS=
	build	CGO_LDFLAGS=
	build	GOARCH=arm64
	build	GOOS=darwin
	build	GOARM64=v8.0
$ file greeter/greeter
greeter/greeter: Mach-O 64-bit executable arm64

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 build_session.py

go mod init wrote a go.mod with the module path and the go line: Go 1.27.1 wrote go 1.27.1, its own version. go build printed nothing, which means it worked, and left an executable named after the last part of the module path, greeter. The file runs without the go command, and du measured it at 2.3 MB: the program’s own code is tiny, and the rest is the Go runtime and the packages it uses.

go version -m prints the build information: What the go command records inside every executable it builds: the Go version, the module path and the build settings. go version -m prints it. that every Go executable carries:

Line What it says
greeter/greeter: go1.27.1 The Go release that built it
path and mod The main package and its module; (devel) because the folder has no version-control tag
-buildmode=exe, -compiler=gc An ordinary executable, built by the standard compiler
CGO_ENABLED=1 and the CGO_ flags cgo, the bridge to C code, was available on this Mac; this program uses none
GOOS=darwin, GOARCH=arm64, GOARM64=v8.0 The system and processor it was built for

Those lines are what you read when a binary misbehaves somewhere else: they say which release built it, for which system, and with which settings.

Versions stamped from version control, since Go 1.24

Since Go 1.24, go build also stamps the main module’s version from the version-control tag or commit when the code is in a repository, with +dirty for uncommitted changes. go version -m on a binary in production then tells you which release or commit it was built from.

Checkpoint

Check: go build and build information

  1. Question 1 of 2 In the folder of a module named example.com/greeter, what does go build write?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: An executable named greeter, in the current folder

    go build writes greeter, which runs without the go command. Use -o to choose another name or folder.

  2. Question 2 of 2 Which command shows the Go release, GOOS and GOARCH that a binary was built with?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: go version -m, followed by the binary's file name

    go version -m greeter/greeter printed go1.27.1, the module, and build lines such as GOOS=darwin and GOARCH=arm64.

One computer builds for every system

GOOS and GOARCH choose the target of a build. Set them in front of go build and the same Mac builds for another operating system and processor; this is cross-compiling: Building a program on one system for another, such as a Linux or Windows executable on a Mac. In Go, the GOOS and GOARCH variables name the target system and processor., and Go needs nothing extra installed for it:

The same module built for Linux and Windows Python · cross_session.py
from session import run

# The same module, built on this Mac for Linux and for Windows.
run("""
mkdir greeter
cp hello.go greeter/main.go
cd greeter && go mod init example.com/greeter
cd greeter && GOOS=linux GOARCH=amd64 go build -o greeter-linux
cd greeter && GOOS=windows GOARCH=amd64 go build -o greeter.exe
file -b greeter/greeter-linux | cut -d, -f1-4
file -b greeter/greeter.exe
du -h greeter/greeter-linux greeter/greeter.exe
""")

Output

$ mkdir greeter
$ cp hello.go greeter/main.go
$ cd greeter && go mod init example.com/greeter
go: creating new go.mod: module example.com/greeter
go: to add module requirements and sums:
	go mod tidy
$ cd greeter && GOOS=linux GOARCH=amd64 go build -o greeter-linux
$ cd greeter && GOOS=windows GOARCH=amd64 go build -o greeter.exe
$ file -b greeter/greeter-linux | cut -d, -f1-4
ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked
$ file -b greeter/greeter.exe
PE32+ executable (console) x86-64, for MS Windows
$ du -h greeter/greeter-linux greeter/greeter.exe
2.3M	greeter/greeter-linux
2.4M	greeter/greeter.exe

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 cross_session.py

Step through the three builds of the two sessions:

Interactive · step by step One main.go, three executables Step through the three builds of the sessions and see what each file is and how big.
One main.go, three executables, step 5 of 5. Showing main.go, greeter (Mach-O arm64, 2.3 MB), greeter-linux (ELF static, 2.3 MB), greeter.exe (PE32+ console, 2.4 MB).go buildGOOS=linuxGOOS=windowsmain.gopackage maingreeterMach-O arm64, 2.3 MBgreeter-linuxELF static, 2.3 MBgreeter.exePE32+ console, 2.4 MB

The drawing shows the whole scene; its 5 steps are listed below.

Every step as text
  1. One source file. The module holds one file, main.go, a copy of hello.go. Nothing in it says which system it is for.
  2. For this Mac. go build with no settings builds for the machine it runs on. file reported a Mach-O 64-bit executable for arm64, and du measured 2.3 MB.
  3. For Linux. GOOS=linux and GOARCH=amd64 in front of the same command made an ELF executable for x86-64 Linux, statically linked, also 2.3 MB. A Linux server runs it with nothing installed.
  4. For Windows. GOOS=windows made a PE32+ console program for x86-64 Windows, 2.4 MB, named greeter.exe with -o, the ending Windows expects of a program.
  5. Three files, one Mac. All three came from the same source on the same Mac, with no compiler for Linux or Windows installed. Each runs only on the system it was built for.

file reported the Linux build as an ELF executable for x86-64, statically linked: An executable that holds every library it needs, so it runs on a machine where none of them is installed. Go's Linux executables are statically linked when cgo is not used.: it holds everything it needs and runs on a Linux server where Go was never installed. The cgo documentation says cgo is turned off by default when cross-compiling, which is why the Linux file needs no C library. The Windows build is a PE32+ console program of 2.4 MB. Each file runs only on the system it was built for: copy the Mac file to a Linux server and the kernel refuses to start it.

Checkpoint

Check: Building for other systems

  1. Question 1 of 2 On a Mac with Apple silicon, which command builds the module for a Linux server with an x86-64 processor?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: GOOS=linux GOARCH=amd64 go build

    Cross-compiling needs only the two variables in front of go build. The session built for linux/amd64 and windows/amd64 on one Mac.

  2. Question 2 of 2 The Linux build ran on a server where Go was never installed. Why did it need nothing else?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: It is statically linked, carries the Go runtime, and cgo was off, so it needs no C library either

    The Go runtime is linked into the file, and with cgo off the program uses no C library, so the file is everything the server needs.

Practise: change, format, vet, build

Install Go first if you have not (the previous lesson), then work in a new folder:

  1. Copy hello.go into it and run go run hello.go: it prints the two lines shown above.
  2. Change main so that it prints a three-line receipt of your own, an item, a quantity and a price per line, using fmt.Printf with %s and %d.
  3. Run gofmt -l . and go vet hello.go until both print nothing.
  4. Run go mod init example.com/receipt, then go build, and start the program it wrote.
  5. Run go version -m on the file and find its GOOS and GOARCH.

Then test the six ideas of this lesson. Each question comes with its explanation, and the weakest idea is asked first:

Practice that adapts to you

Practise this lesson

12 questions about 6 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 12 Which declaration can start a Go program?

    Choose one answer.

    Show the answer: Question 1 of 12

    Answer: func main(), in package main

    The specification asks for a package named main that declares a func main with no arguments and no results.

  2. Question 2 of 12 What does hello.go print?

    What does this program print? Choose one answer.

    // hello.go: a whole Go program. It starts in func main of package main.
    package main
    
    import "fmt"
    
    func main() {
    	name := "Asha"
    	fmt.Println("Hello,", name)
    	fmt.Printf("%s has %d letters\n", name, len(name))
    }
    Show the answer: Question 2 of 12

    Answer: it prints

    Hello, Asha
    Asha has 4 letters
    

    fmt.Println("Hello,", name) prints Hello, Asha and a newline; fmt.Printf("%s has %d letters\n", name, len(name)) prints Asha has 4 letters, because Asha has four bytes.

  3. Question 3 of 12 What does import _ "image/png" do?

    Choose one answer.

    Show the answer: Question 3 of 12

    Answer: It imports the package only for what it does when the program starts

    A blank import runs the package's initialization, which for image/png registers the PNG decoder, while the file itself uses none of its names.

  4. Question 4 of 12 What does the compiler say about this function?

    Read the code, then choose one answer.

    func main() {
        count := 0
        if true {
            count := 5
        }
        fmt.Println(count)
    }
    Show the answer: Question 4 of 12

    Answer: declared and not used, for the count of the inner block

    The unused-variable error often reveals this bug: := inside a block declares a new variable instead of assigning the outer one. Write count = 5 to assign.

  5. Question 5 of 12 After which of these, as the last token of a line, does the compiler insert a semicolon? Choose every one.

    Choose every answer that is right.

    Show the answer: Question 5 of 12

    Answer:

    • An identifier such as main
    • A closing parenthesis )
    • The keyword return

    The rule adds a semicolon after an identifier, a literal, one of four keywords, or ++, --, ), ] and }. Lines that end with {, a comma or an operator continue on the next line.

  6. Question 6 of 12 Why does this function not compile?

    Read the code, then choose one answer.

    func total() int {
        return
        1 + 2
    }
    Show the answer: Question 6 of 12

    Answer: A semicolon is inserted after return, so it returns nothing, and 1 + 2 is a statement on its own

    Keep the value on the line of the return. Go 1.27.1 reports three errors: the return gives no value where an int is wanted, the constant 3 is not used, and the function is missing a return at its end.

  7. Question 7 of 12 Which gofmt flag rewrites the files in place?

    Choose one answer.

    Show the answer: Question 7 of 12

    Answer: -w

    In the session, gofmt -w tidy/messy.go rewrote the file, and the next gofmt -l printed nothing.

  8. Question 8 of 12 Why run go vet when the program already compiles?

    Choose one answer.

    Show the answer: Question 8 of 12

    Answer: It reports code that compiles but is probably wrong, such as a Printf verb that does not fit its argument

    A format string is just a string to the compiler. vet reads it, sees that %d does not fit a string, and reports it before the program ever runs.

  9. Question 9 of 12 Which command leaves an executable beside your code?

    Choose one answer.

    Show the answer: Question 9 of 12

    Answer: go build

    go run is for trying a program, go build for the file you test, copy or ship.

  10. Question 10 of 12 go version -m showed mod example.com/greeter (devel). Why (devel)?

    Choose one answer.

    Show the answer: Question 10 of 12

    Answer: The module's folder had no version-control tag or commit to stamp into the binary

    Built inside a repository, the main module's version comes from the tag or commit, with +dirty for uncommitted changes; the session's folder had none.

  11. Question 11 of 12 uname -m on a Linux server prints aarch64. Which GOARCH do you build with?

    Choose one answer.

    Show the answer: Question 11 of 12

    Answer: arm64

    Go's names differ from the kernel's: x86_64 is amd64 and aarch64 is arm64.

  12. Question 12 of 12 Which settings build the greeter module, on the Mac, for a Windows laptop with an Arm processor?

    Choose one answer.

    Show the answer: Question 12 of 12

    Answer: GOOS=windows GOARCH=arm64 go build

    Every target is a pair, GOOS and GOARCH. go tool dist list prints every pair the toolchain can build for.

Interview questions

Warm-up (fresher): What is the difference between go run and go build?

go run compiles a main package, links it into an executable in a temporary folder and runs it at once, passing on any arguments after the package. Since Go 1.24 that executable is also kept in the build cache, so running unchanged code again skips the build, and by default go run leaves out the information debuggers use. go build compiles and links the same package but writes the executable beside your code, or to the file named by -o, and does not run it. Use go run while you write and try a program, and go build to make the file you test, copy or ship. Both build for the system named by GOOS and GOARCH, and only go build leaves a file you can copy to another machine.

Two longer interview questions of this module start from this lesson:

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Fresher to mid

    Go refuses to compile a function with an unused local variable, or a file with an unused import, yet it accepts an unused function or an unused package-level variable. Why the difference, and how do you work with the rule while you debug?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    A binary built on a developer's Mac runs fine there, but the same file copied to a Linux server fails with "exec format error". Explain why, how you would build it correctly, and how you would check any binary before it ships.

    Model answer, Pro. First step and follow-ups

Key takeaways

  • A program is the package main with a func main, and go run compiles it into a temporary executable, runs it and keeps a copy in the build cache for the next run.
  • An unused import or an unused local variable stops the build; _ throws a value away on purpose, briefly.
  • The compiler inserts a semicolon after a line that ends with ), so an opening brace must stay on the line that starts its block.
  • gofmt gives every file the one standard layout, and go vet reports code that compiles but is probably wrong, such as a Printf verb that does not fit its argument.
  • go mod init and go build turn the program into one executable, 2.3 MB here, whose build information go version -m prints.
  • GOOS and GOARCH build the same code for other systems from one computer; the Linux build was statically linked.

Terms in this lesson

blank identifier
The name _ (an underscore), which takes a value and throws it away. It lets code ignore a result on purpose, or import a package only for what it does when it starts.
build information
What the go command records inside every executable it builds: the Go version, the module path and the build settings. go version -m prints it.
cross-compiling
Building a program on one system for another, such as a Linux or Windows executable on a Mac. In Go, the GOOS and GOARCH variables name the target system and processor.
go vet
The go command that reports code which compiles but is probably wrong, such as a Printf verb that does not fit its argument.
gofmt
The tool that lays out Go source in the one standard format, with tabs for indentation and spaces for alignment. gofmt -l lists the files it would change and gofmt -w rewrites them.
package main
The package that makes a program. It must be named main and declare a func main that takes no arguments and returns nothing; running the program runs that function.
semicolon insertion
Go's rule that a semicolon is added after a line whose last token could end a statement, such as a name, a literal or a closing bracket. It is why an opening brace must stay on the line before it.
statically linked
An executable that holds every library it needs, so it runs on a machine where none of them is installed. Go's Linux executables are statically linked when cgo is not used.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.