Install Go
# Manjaro linux
sudo pacman -Syu go
Structure of Go Code
- Packages:
- A bunch of go files :smile:.
- Modules:
- A bunch of packages :smile:.
- So basically when we initiate a new project we are creating a new module.
go mod init github.com/kasir-barati/golang
[!TIP]
The name of module usually is the URL of a GitHub repository. But we can use any name we want, i.e.
git mod init test.

Now you can start creating new packages:
code src/utils/main.go
- This is a special package, it is the entry point of the program.
- It is where the compiler starts executing the code from.
- You must define a function called
mainin this package. This is mandatory.
Now it’s time to build and run the program:
go build src/utils/main.go
- This will create a binary file called
mainat the root of the project. - I gitignore the output of this command.
Now let’s run the program:
./main
[!TIP]
You can also run the program with the
go run src/utils/main.gocommand.
Variables & Constants
- To declare a variable we use the
varkeyword. - The type of the variable can be inferred from the value.
- We can also specify the type of the variable explicitly.
var name string = "John"
[!TIP]
We must use every variable we define, otherwise the compiler will throw an error.
| Variable Types | ||||
|---|---|---|---|---|
int, uint |
int8, uint8 |
int16, uint16 |
int32, uint32 |
int64, uint64 |
| - | - | - | float32 |
float64 |
string |
- | - | - | - |
rune |
- | - | - | - |
bool |
- | - | - | - |
[!TIP]
Overflow:
The size of the variable matters and in runtime you might run into the issue of overflow.
var score int16 = 32767 score++ println(score) // -32768 var avg float32 = 999999.99 fmt.Println(avg) // 1e+06
[!NOTE]
lenVSutf8.RuneCountInString:
lenof a string is the number of bytes, NOT the number of characters!var name string = "Öl" println(len(name)) // 3To get the number of characters we can use the
utf8package.import "unicode/utf8" var name string = "Öl" println(utf8.RuneCountInString(name)) // 2
- We can use the
inttype which picksint23orint64based on the system architecture. - Int division is always an integer.
runes are equivalent ofchartypes in c++.- The default value of a variable depends on its type, e.g.
intis0,stringis"", etc. - We can use the
:=operator to declare and initialize a variable in one line, e.g.name := "Mahdi".- Sometimes it is better to be as explicit as possible,
res := someFunc().
- Sometimes it is better to be as explicit as possible,
[!NOTE]
constis immutable & they must be initialized at declaration.
Functions
- We can define functions in Go by using the
funckeyword. - We need to let the compiler know the return type of the function + the types of the parameters.
package main
import (
"fmt"
)
func main() {
var num1 int = 11
var num2 int = 20
var result int = add(num1, num2)
fmt.Println(result)
}
func add(num1 int, num2 int) int {
return num1 + num2
}
- We can return multiple values from a function.
- Note, this ain’t the same as
tuples in Python.
- Note, this ain’t the same as
func divide(numerator int, denominator int) (int, int) {
var result int = numerator / denominator
var remainder int = numerator % denominator
return result, remainder
}
[!TIP]
A common pattern in Go is to return an error as the last value:
import "errors" func divide(numerator int, denominator int) (int, int, error) { if denominator == 0 { return 0, 0, errors.New("cannot divide by zero") } var result int = numerator / denominator var remainder int = numerator % denominator return result, remainder, nil } var divisionResult, divisionRemainder, error = divide(num1, num2) if error != nil { fmt.Println(error.Error()) return }
Logical Operators & Comparison Operators
== |
!= |
&& |
|| |
> |
< |
if res == 10 { |
if err != nil { |
if num2 > 0 && num1 > 0 { |
if res == 2 || res == 4 { |
if num1 > 0 { |
if num2 < 0 { |
[!NOTE]
- If the first statement in an
ifstatement is true, the second statement is NOT evaluated for the||operator.- If the first statement in an
ifstatement is false, the second statement is NOT evaluated for the&&operator.
switch Statement
- No need to use
breakin Go.- It is implied.
- You can have a
switchstatement without a condition.
var num int = 10
switch num {
case 1, 2:
println("num is 1 or 2")
case 10:
println("num is 10")
case 20:
println("num is 20")
default:
println("num is not 10 or 20")
)
switch {
case num > 0:
println("num is positive")
// ...
}
Arrays
- Fixed-size.
- Homogeneous.
- Indexed.
- Zero-based.
import "fmt"
var scores [5]int = [5]int{1, 2, 3, 4, 5}
fmt.Println(scores[:]) // [0 0 0 0 0]
fmt.Println(scores[1:3]) // [2 3]
[!TIP]
scores := [...]int{1, 2, 3, 4, 5} var names [3]string
Slices
- Wrappers around arrays.
- Omit the size of the array, and you’ll have your slice.
- It will automatically resizes the array for you.
- This has performance implications.
- So better to think carefully about the size/capacity of the slice.
var scores []int
scores = append(scores, 1)
[!TIP]
Use speared operator to append a list of values to a slice:
numbers := []int{1, 2, 3, 4, 5} scores = append(scores, numbers...)
make Function
- Creates a slice with a specified length and capacity.
- The capacity is the size of the underlying array.
- This means that you can create a bigger slice than what you currently need in order to avoid recreating the underlying array when you need to add more elements.
var scores []int = make([]int, 5, 10)