GO · STEP 1 · INTRO
Go · Intro to the language
Go 1.27 (any 1.22+ works): variables, input, conditionals, loops, slices, maps and functions — each shown first in the JavaScript you know, then in Go.
What you will learn#
- Creating Variables in a New Language
- Conditionals in a New Language
- Looping in a New Language
- Collections in a New Language
- Writing Functions in a New Language
Getting Started#
Install the current Go from go.dev/dl (1.27.3 as of this writing; anything from 1.22 up runs everything on this page), then confirm it in a terminal:
go versionGo programs live in a module. Make a folder, initialise a module in it, and run the code:
mkdir hello && cd hellogo mod init example/hellogo run .go run . compiles and runs every .go file in the folder; go build produces a single binary you can copy anywhere. If you'd rather not install anything yet, the official Go Playground runs today's examples in the browser.
WHY: Go is compiled and statically typed. Mistakes JavaScript would only show you at runtime (a typo in a variable name, calling a function with the wrong number of arguments) stop the compile instead. It feels strict on day one and saves you hours by week two.
Creating Variables#
How we did it in Javascript
// We create constant variables with the const keywordconst myConstant = 5// We create re-assignable variables with the let keywordlet myVariable = "Hello World" // We print variables to the console using console.logconsole.log(myConstant)console.log(myVariable)How we do this in Go
package main import "fmt" // fmt has Println for printing to the console // Constants use the const keyword; Go style is mixedCaps, not ALL_CAPSconst myConstant = 5 // Variables use the var keyword. The type can be written out...var myVariable string = "Hello World" func main() { // ...or inferred with := (the short declaration, only allowed inside functions) myOther := "inferred as a string" fmt.Println(myConstant) fmt.Println(myVariable) fmt.Println(myOther)}Every Go file starts with a package line, imports what it uses, and the main function of package main is where the program starts. Two rules that will bite you early: an unused variable or import is a compile error, and a variable's type never changes after it is declared (myVariable = 5 will not compile).
Receiving Input#
In JavaScript in the browser, input comes from forms or prompt. In Node, reading from the terminal goes through the readline module; the promise-based version reads cleanly with await:
// Node: ask a question in the terminal and wait for the answerimport readline from "node:readline/promises"import { stdin as input, stdout as output } from "node:process" const rl = readline.createInterface({ input, output })const name = await rl.question("Who are you? ")console.log(`Hey there ${name}!`)rl.close()How would we do that in Go?
package main import ( "bufio" "fmt" "os") func main() { fmt.Print("Who are you? ") // a Scanner reads os.Stdin one line at a time scanner := bufio.NewScanner(os.Stdin) scanner.Scan() // blocks until the user presses Enter name := scanner.Text() // the line that was typed, without the newline fmt.Println("Hey there " + name + "!")}You will also see fmt.Scanln(&name) in older tutorials. It works, but it stops at the first space, so "Arthur Bernier" comes back as "Arthur". bufio.Scanner reads the whole line. Either way the result is a string; convert with strconv.Atoi(text) when you need a number.
Conditionals#
If statements in Javascript
const num = 5 if (num > 3) { console.log("num is greater than 3")} else if (num > 1) { console.log("num is greater than 1")} else { console.log("num is 1 or less")}If statements in Go
package main import "fmt" func main() { num := 5 // type is inferred as int // no parentheses around the condition; the braces are required if num > 3 { fmt.Println("num is greater than 3") } else if num > 1 { fmt.Println("num is greater than 1") } else { fmt.Println("num is 1 or less") }}Three differences from JavaScript: no parentheses, braces are never optional, and else must sit on the same line as the closing } (a line break there is a syntax error because Go inserts semicolons at line ends). &&, || and ! are the same; there is only == because Go never coerces types.
While Loops#
In Javascript
let counter = 0 // This will loop 10 timeswhile (counter < 10) { console.log(counter) counter += 1}In Go
package main import "fmt" func main() { counter := 0 // Go has no while keyword: a for loop with only a condition is the while loop for counter < 10 { fmt.Println(counter) counter++ }}for is Go's only loop. The three-clause form is the one you know from JavaScript, and since Go 1.22 you can range over a number directly:
for i := 0; i < 10; i++ { fmt.Println(i)} for i := range 10 { // 0 through 9 fmt.Println(i)}10 Minute Exercise#
Write the code to do the following:
- Loop 10 times starting the counter at 0
- On each loop if the counter is even print "it's even"
- If odd, print "meow" if the number is divisible by 3
- Otherwise print nothing
Collections#
In Javascript we have arrays and objects
const myArray = [1, 2, 3] console.log(myArray) // logging the entire arrayconsole.log(myArray[0]) // logging an individual item const myObject = { cheese: "gouda", bread: "rye",} console.log(myObject) // logging the entire objectconsole.log(myObject.cheese) // logging a property using dot notationconsole.log(myObject["bread"]) // logging a property using square bracket notationIn Go we use slices and maps
package main import "fmt" func main() { mySlice := []int{1, 2, 3} // a slice: a growable list where every item has the same type fmt.Println(mySlice) // [1 2 3] fmt.Println(mySlice[0]) // 1 fmt.Println(len(mySlice)) // 3 mySlice = append(mySlice, 4) // append returns the grown slice; keep the result // range gives you the index and the value; _ throws the index away for _, item := range mySlice { fmt.Println(item) } // a map: keys and values are typed (string keys, string values here) myMap := map[string]string{ "cheese": "gouda", "bread": "rye", } fmt.Println(myMap) // map[bread:rye cheese:gouda] fmt.Println(myMap["cheese"]) // gouda — square brackets only, there is no dot access fmt.Println(myMap["jam"]) // "" — a missing key returns the zero value, not undefined}Go also has arrays ([3]int, fixed length, rarely used directly) — a slice is a window onto one. For "is this key present?" use the two-value form: value, ok := myMap["jam"].
10 Minute Exercise#
Look up slices in A Tour of Go and the slices package on pkg.go.dev, and apply what you find to the following list.
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}- How to find a list's length (
len) - How to loop over a list (
for i, v := range list) - How to add and remove items from a list (
append,slices.Delete, or re-slicing withlist[1:])
Functions#
in Javascript
const addNums = (x, y) => { return x + y} console.log(addNums(5, 5))In Go
package main import "fmt" // parameters and the return value are typed; x, y int means both are intsfunc addNums(x, y int) int { return x + y} func main() { fmt.Println(addNums(5, 5))}The pattern you'll see everywhere in Go code is a function that returns two values, the result and an error, and a caller that checks the error before using the result:
package main import ( "fmt" "strconv") func main() { n, err := strconv.Atoi("42") // (int, error) if err != nil { fmt.Println("not a number:", err) return } fmt.Println(n + 1)}There are no exceptions to catch; errors are ordinary values you return and check. Anonymous functions exist too (func(x, y int) int { return x + y }) and can be assigned to variables or passed as arguments, like arrow functions.
10 minute exercise#
Write the following functions
subNumsthat takes two arguments and returns their differencesayHellothat takes a name as an argument and says hello to that namesayHelloAdvthat takes a map with a name and age key and prints "hello {name}, how does it feel to be {age} years old" (fmt.Printfwith%sand%dhelps here)loopertakes one slice as an argument, loops over the slice and prints each item individually
Resources to Learn More#
- A Tour of Go — the official interactive walk-through; Basics, Flow control and More types cover everything on this page
- Tutorial: Get started with Go — modules,
go run, and importing a package - Effective Go — why Go code looks the way it does (naming, errors, slices)
- Package fmt —
Println,Printfand the%v/%s/%dverbs
See also