Go
Go is an open-source programming language that makes it easy to build simple, reliable, and efficient software.
Go is a statically typed, compiled programming language. Go is similar to C. It is memory safe and has garbage
collection. Go has high speed compilation and excellent tooling support. It contains built-in primitives for
concurrency.
command description
go build compiles packages and dependencies
go env prints Go environment information
go get adds dependencies to current module and installs them
go install compiles and installs packages and dependencies
go list lists packages and modules
go run compiles and runs a Go program
go version prints Go version
Go first example
$ mkdir simple
$ cd simple
$ go mod init zetcode.com/simple
simple.go
package main
import "fmt"
func main() {
fmt.Println("Go simple example")
}
$ go run simple.go
Go comments
Comments are used by humans to clarify source code. There are two types of comments in Go: single line
comments (//) and multi-line comments (/* */).
comments.go
package main
import "fmt"
/*
This is comments.go
Author: Jan Bodnar
ZetCode 2020
*/
// Program starts here
func main() {
fmt.Println("Go first example")
}
Go user input
The Scanf function scans text read from standard input, storing successive space-separated values into successive
arguments as determined by the format. It returns the number of items successfully scanned.
read_input.go
package main
import "fmt"
func main() {
var name string
fmt.Print("Enter your name: ")
fmt.Scanf("%s", &name)
fmt.Println("Hello", name)
}
Go conditionals
conditionals.go
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
num := -5 + rand.Intn(10)
if num > 0 {
fmt.Println("The number is positive")
} else if num == 0 {
fmt.Println("The number is zero")
} else {
fmt.Println("The number is negative")
}
}
Go for loop
for_loop.go
package main
import "fmt"
func main() {
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
}
for_loop2.go
package main
import "fmt"
func main() {
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
sum := 0
for _, num := range nums {
sum += num
}
fmt.Println(sum)
}
Go switch statement
switch.go
package main
import (
"fmt"
"runtime"
)
func main() {
os := runtime.GOOS
switch os {
case "windows":
fmt.Println("Windows")
case "darwin":
fmt.Println("MAC operating system")
case "linux":
fmt.Println("Linux")
default:
fmt.Printf("%s.\n", os)
}
}
Go variadic function
A variadic function can accept variable number of parameters. For instance, when we want to calculate the sum
of values, we might have four, five, six etc. values to pass to the function.
variadic.go
package main
import "fmt"
func main() {
s1 := sum(1, 2, 3)
s2 := sum(1, 2, 3, 4)
s3 := sum(1, 2, 3, 4, 5)
fmt.Println(s1, s2, s3)
}
func sum(nums ...int) int {
res := 0
for _, n := range nums {
res += n
}
return res
}
Go defer function call
defercall.go
package main
import "fmt"
func main() {
fmt.Println("begin main")
defer sayHello()
fmt.Println("end main")
}
func sayHello() {
fmt.Println("hello")
}
Go filter function
filtering.go
package main
import "fmt"
type User struct {
name string
occupation string
married bool
}
func main() {
u1 := User{"John Doe", "gardener", false}
u2 := User{"Richard Roe", "driver", true}
u3 := User{"Bob Martin", "teacher", true}
u4 := User{"Lucy Smith", "accountant", false}
u5 := User{"James Brown", "teacher", true}
users := []User{u1, u2, u3, u4, u5}
married := filter(users, func(u User) bool {
if u.married == true {
return true
}
return false
})
teachers := filter(users, func(u User) bool {
if u.occupation == "teacher" {
return true
}
return false
})
fmt.Println("Married:")
fmt.Printf("%v\n", married)
fmt.Println("Teachers:")
fmt.Printf("%v\n", teachers)
}
func filter(s []User, f func(User) bool) []User {
var res []User
for _, v := range s {
if f(v) == true {
res = append(res, v)
}
}
return res
}
Go make map
main.go
package main
import "fmt"
func main() {
benelux := make(map[string]string)
benelux["be"] = "Belgium"
benelux["nl"] = "Netherlands"
benelux["lu"] = "Luxembourgh"
fmt.Println(benelux)
fmt.Printf("%q\n", benelux)
}
Go closure
A Go closure is an anonymous nested function which retains bindings to variables defined outside the body of
the closure.
anonymous.go
package main
import "fmt"
func main() {
sum := func(a, b, c int) int {
return a + b + c
}(3, 5, 7)
fmt.Println("5+3+7 =", sum)
}
Go arithmetic operators
Symbol Name
+ Addition
- Subtraction
* Multiplication
/ Division
% Remainder
Go Boolean operators
Symbol Name
&& logical and
|| logical or
! negation
Go comparison operators
Comparison operators are used to compare values. These operators always result in a boolean value.
Symbol Meaning
< less than
<= less than or equal to
> greater than
>= greater than or equal to
== equal to
!= not equal to
Go channel operator
A channel is a typed conduit through which we can send and receive values with the channel operator <-.
channel_op.go
package main
import "fmt"
func main() {
messages := make(chan string)
go func() { messages <- "hello" }()
msg := <-messages
fmt.Println(msg)
}
Go read input with Scanf
read_input.go
package main
import "fmt"
func main() {
var name string
fmt.Print("Enter your name: ")
fmt.Scanf("%s", &name)
fmt.Println("Hello", name)
}
read_input3.go
package main
import (
"os"
"bufio"
"fmt"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter your name: ")
name, _ := reader.ReadString('\n')
fmt.Printf("Hello %s\n", name)
}
Go closure middleware
The middleware are functions that execute during the lifecycle of a request to a server. The middleware is
commonly used for logging, error handling, or compression of data.
middleware.go
package main
import (
"fmt"
"log"
"net/http"
"time"
)
func main() {
http.HandleFunc("/now", logDuration(getTime))
fmt.Println("Server started at port 8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
func logDuration(f func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
f(w, r)
end := time.Now()
fmt.Println("The request took", end.Sub(start))
}
}
func getTime(w http.ResponseWriter, r *http.Request) {
now := time.Now()
_, err := fmt.Fprintf(w, "%s", now)
if err != nil {
log.Fatal(err)
}
}
Go check if file exists
main.go
package main
import (
"errors"
"fmt"
"os"
)
func main() {
_, err := os.Stat("words.txt")
if errors.Is(err, os.ErrNotExist) {
fmt.Println("file does not exist")
} else {
fmt.Println("file exists")
}
}
We call the os.Stat function on the file. If the function returns the os.ErrNotExist error, the file does not exist.
Go create file
The os.Create function creates or truncates the given file. If the file already exists, it is truncated. If the file does
not exist, it is created with mode 0666.
main.go
package main
import (
"fmt"
"log"
"os"
)
func main() {
file, err := os.Create("empty.txt")
defer file.Close()
if err != nil {
log.Fatal(err)
}
fmt.Println("file created")
}
Go delete file
main.go
package main
import (
"fmt"
"log"
"os"
)
func main() {
err := os.Remove("words.txt")
if err != nil {
log.Fatal(err)
}
fmt.Println("file deleted")
}
Go file size
main.go
package main
import (
"fmt"
"log"
"os"
)
func main() {
fInfo, err := os.Stat("words.txt")
if err != nil {
log.Fatal(err)
}
fsize := fInfo.Size()
fmt.Printf("The file size is %d bytes\n", fsize)
}
Go file last modified time
main.go
package main
import (
"fmt"
"log"
"os"
)
func main() {
fileName := "words.txt"
fileInfo, err := os.Stat(fileName)
if err != nil {
log.Fatal(err)
}
mTime := fileInfo.ModTime()
fmt.Println(mTime)
}
Go read file
main.go
package main
import (
"fmt"
"io/ioutil"
"log"
)
func main() {
content, err := ioutil.ReadFile("words.txt")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(content))
}
Go write file
main.go
package main
import (
"fmt"
"io/ioutil"
"log"
)
func main() {
fileName := "data.txt"
val := "old\nfalcon\nsky\ncup\nforest\n"
data := []byte(val)
err := ioutil.WriteFile(fileName, data, 0644)
if err != nil {
log.Fatal(err)
}
fmt.Println("done")
}
Go copy file
main.go
package main
import (
"io/ioutil"
"log"
)
func main() {
src := "words.txt"
dest := "words2.txt"
bytesRead, err := ioutil.ReadFile(src)
if err != nil {
log.Fatal(err)
}
err = ioutil.WriteFile(dest, bytesRead, 0644)
if err != nil {
log.Fatal(err)
}
}
Scanf
main.go
package main
import (
"fmt"
"log"
)
func main() {
var n1, n2, n3, n4, n5 int
fmt.Print("Enter five numbers separated by comma and space: ")
_, err := fmt.Scanf("%d, %d, %d, %d, %d", &n1, &n2, &n3, &n4, &n5)
if err != nil {
log.Fatal(err)
}
sum := n1 + n2 + n3 + n4 + n5
fmt.Printf("The sum of five numbers is: %d\n", sum)
}
Go errors.New
A new error can be created with the errors.New function. It returns an error that formats as the given text.
new_error.go
package main
import (
"errors"
"fmt"
)
func main() {
err := errors.New("Some error")
if err != nil {
fmt.Println(err)
}
}
Go errors.Is
isfun.go
package main
import (
"errors"
"fmt"
"log"
"os"
)
func main() {
if _, err := os.Open("data.txt"); err != nil {
if errors.Is(err, os.ErrNotExist) {
log.Fatal("file does not exist\t", err)
} else if errors.Is(err, os.ErrPermission) {
log.Fatal("insufficient permissions\t", err)
} else {
log.Fatal(err)
}
}
fmt.Println("...")
}
Go fmt.Errorf
circle_area.go
package main
import (
"fmt"
"math"
"os"
)
func area(radius float64) (float64, error) {
if radius < 0 {
return 0, fmt.Errorf("radius %0.2f is less than zero", radius)
}
return math.Pi * radius * radius, nil
}
func main() {
radius := -7.0
area, err := area(radius)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("Area of circle %0.2f", area)
}