Language Syntax
Below is a basic overview of the language syntax, I would recommend as you are reading this you play with the code in the Go playground: https://play.golang.org/ or take the Go language tour which these notes are based on https://tour.golang.org
Packages
Basics
no semi colons
minimal syntax, no parens etc.
Imports
Exported Names
Functions
parameters
multiple return values
- named return values
- variables
- short declaration
- basic types
- zero values
- type conversion
- type inference
For Loops
Unlike many other languages that have multiple looping keywords, Go only supports the "for" looping construct. It has three basic parts, INIT STATEMENT, CONDITION, POST STATEMENT
for INIT STATEMENT; CONDITION; POST STATEMENT {
}
An example loop would be:
var sum int
for i:=0; i<100; i++ {
sum += i
}
Note that there are no parens () like most other languages. The init statement, condition and post statement are optional, for example you could write:
var sum int
for sum<100 {
sum += 1
}
At which point, the for loop has become a while statement. And dropping the condition, we can loop forever by simply writing:
for {
...
}
If Statement
If statements are pretty standard, again note no parens () needed, also the else HAS TO BE on the same line as the closing }
if x > 10 {
...
} else {
...
}
One neat thing you can do with if statements is execute a statement before the condition is checked. This is useful if you want to write more compact code like:
if isValid := isValidLogin("bob"); !isValid {
fmt.Println("bob does not exist")
} else {
fmt.Println("hello bob")
}
Generally you see this pattern when checking error return values from a function. The only downside is that in the above example the isValid variable is only accessible inside the if statement true/false body, so if you want to access it outside the if statement you would have to declare the variable outside the if statement and not use the short initializer syntax.
Switch
Go's switch statement is different to many other languages, especially JavaScript in that you don't fall through cases automatically. Once a case is matched, subsequent cases will not be executed, if you want to fall through you have to use the explicit "fallthrough" statement
switch login {
case "Bob":
fmt.Println("hi Bob")
case "Frank":
fmt.Println("hi Frank")
fallthrough
case "Joe":
fmt.Println("hi Joe")
}
You can also omit the switch condition, this is equivalent to writing "switch true {" in which case the first case statement that evaluates to true will execute.
Defer
The defer statement allows you to schedule a function to execute before you exit the current function. For example you may need to close a resource or unlock a mutex, using defer makes this easy. In the example below, there are multiple return statements in the function, instead of having to call mutex.Unlock() multiple times in the function (potentially introducing bugs if you forget), you simply call defer with mutex.Unlock() and that will be executed when the function exits.
func doIt(x bool) int {
var mutex sync.Mutex
mutex.Lock()
defer mutex.Unlock()
if x {
return 99
} else {
return 50
}
}
NOTES: The function you pass to defer is not executed until the function exits, BUT... the parameters you pass to the function are evaluated at the time defer is called, in the example below, event though we update the age variable after calling defer, it is not reflected in the function call, which still prints "30" (note if the parameter was a reference type, updating fields would obviously still be reflected in the defer call:
func main() {
age := 30
defer printAge(age)
age = 50
}
func printAge(age int) {
fmt.Println(age)
}
// Output: 30
You can also call defer multiple times, the defer calls are placed in a stack and evaluated last-in-first-out.