You are on page 1of 44

Advance Computer Programming – GO

Lecture – 05
Maps and Packages

Instructor: Syed Mujtaba Hassan


Email: mujtaba.hassan@riphah.edu.pk
Session: Fall 2022
Riphah School of Computing and Innovation (RSCI)
Riphah International University, Lahore
Golang Maps

In Go language, a map is a powerful, ingenious, and versatile data structure.


Golang Maps is a collection of unordered pairs of key-value. It is widely used
because it provides fast lookups and values that can retrieve, update or delete with
the help of keys.
• It is a reference to a hash table.
• Due to its reference type it is inexpensive to pass, for example, for a 64-bit
machine it takes 8 bytes and for a 32-bit machine, it takes 4 bytes.
• In the maps, a key must be unique and always in the type which is comparable
using == operator or the type which support != operator. So, most of the built-
in type can be used as a key like an int, float64, rune, string, comparable array
and structure, pointer, etc. The data types like slice and noncomparable arrays
and structs or the custom data types which are not comparable don’t use as a
map key.
Continue…

• In maps, the values are not unique like keys and can be of any type like int,
float64, rune, string, pointer, reference type, map type, etc.
• The type of keys and type of values must be of the same type, different types of
keys and values in the same maps are not allowed. But the type of key and the
type values can differ.
• The map is also known as a hash map, hash table, unordered map, dictionary, or
associative array.
• In maps, you can only add value when the map is initialized if you try to add
value in the uninitialized map, then the compiler will throw an error.
Important Questions

What is a Golang map?


Why is it useful?
How does it compare to a slice?
How do you declare a map?
How do you initialize a map in Go?
How to creating and initializing Maps?

Simple: In this method, you can create and initialize a map without the use
of make() function:
Creating Map: You can simply create a map using the given syntax:

// An Empty map
map[Key_Type]Value_Type{}

// Map with key-value pair


map[Key_Type]Value_Type{key1: value1, ..., keyN: valueN}
Go program to illustrate how to create and initialize maps
package main
import "fmt"
func main() {
// Creating and initializing empty map
// Using var keyword
var map_1 map[int]int
// Checking if the map is nil or not
if map_1 == nil {
fmt.Println("True")
} else {
fmt.Println("False")
}
Creating and initializing a map Using shorthand declaration
and using map literals

map_2 := map[int]string{
90: “Animal",
91: “Birds",
92: “Pets",
}
fmt.Println("Map-2: ", map_2)
}
Continue…

As usual in Go, we can declare our variable first, and then assign it a value:

var menu map[string]float64


menu = map[string]float64{
"eggs": 1.75,
"bacon": 3.22,
"sausage": 1.89,
}
Continue…

Alternatively, we can use the short declaration syntax to do both operations in one step:

menu := map[string]float64{
"eggs": 1.75,
"bacon": 3.22,
"sausage": 1.89,
}
Existence of key value item

func main() {
// Creating struct instances
a2 := Address{Name: “Mujtaba", city: “Lahore", Pincode: 5600}
a1 := Address{“Hassan", “Okara", 5400}
a3 := Address{Name: “Ahmad", city: “Islamabad", Pincode: 2700}
// Declaring a map
var mp map[Address]int
// Checking if the map is empty or not
if mp == nil {
fmt.Println("True")
} else {
fmt.Println("False")
}
// Declaring and initialising
// using map literals
sample := map[Address]int{a1: 1, a2: 2, a3: 3}
fmt.Println(sample)
}
Golang Slices
It is possible to create a slice of map data type in Golang as well. In fact, a slice
can be created of any data type in Go. Below is a simple example to create a slice
of map
package main
import "fmt"
func main() {
maps := make([]map[string]string, 3)
map1 := make(map[string]string)
map1["1"] = "a"
map2 := make(map[string]string)
map2["2"] = "b"
map3 := make(map[string]string)
map3["3"] = "c"
maps[0] = map1
maps[1] = map2
maps[2] = map3
for _, m := range maps {
fmt.Println(m)
}
}
Continue…

We also created a slice of map data type like this.

map1 := make(map[string]string)
map1["1"] = "a"

map2 := make(map[string]string)
map2["2"] = "b"

map3 := make(map[string]string)
map3["3"] = "c"
Go Standard Libraries
Continue…
Continue…
Continue…
Continue…

You access the slice items by referring to the index number.

package main
import "fmt"
func main() {
var intSlice = []int{10, 20, 30, 40}
fmt.Println(intSlice[0])
fmt.Println(intSlice[1])
fmt.Println(intSlice[0:3])
}
Continue…
Continue…
Continue…
Continue…
Continue…
Continue…
Continue…
Continue…
Continue…
Continue…
Continue…
Continue…
Continue…

Source: https://pkg.go.dev/std
RegEx in GoLang
A regular expression is a sequence of characters that is used for searching and
replacing text and pattern matching.
Note: This expression is not the property of just one particular programming
language; instead, it is supported by multiple languages.
Continue…
Regular expression patterns
There are certain expressions that need to be used to search and match patterns;
some of these are given in the table below.
Expression Description

Used to find any of the


characters or numbers
[] specified between the
brackets.

\d Used to find any digit.

\D Used to find anything that


is not a digit.

\d+ Used to find any number of


digits.

Used to find any number


x* (can be zero) of
occurrences of x.
Continue…

The GoLang standard package for writing regular expressions is called


regexp. The package uses RE2 syntax standards that are also used by other
languages like Python, C, and Perl.
In order to use a regular expression in Go, it must first be parsed and returned
as a regexp object.

package main
import (
"fmt"
"regexp"
)

func main() {
re := regexp.MustCompile("ck$")
fmt.Println(re.FindString("hack"))
}
Golang Sync package

In Golang recommended way to dealing with concurrency is sharing by


communication. Go has introduced a concept called channel for achieve this
concept but there may be scenarios still need to go with traditional approach
communicate by sharing so lot of required tool for second approach are rest in
Sync package. Discussing all provided components in the sync package is the idea
of this article .
1. Atomic
2. Mutex
3. RWmutex
4. SyncMap
5. SyncPool
6. WaitGroup
Atomic
Atomic operations are more primitive than other synchronization mechanism.
They are lockless and generally implemented at hardware level. So atomics are
used in implementing other synchronization techniques also.
func AtomicCounterDemo(){
var opt uint64
var wg sync.WaitGroup
for i:=0;i<50;i++{
wg.Add(1)
go func() {
for c:=0;c<1000;c++{
//because opt is been accessed by multiple goroutines
//unless otherwise atomic package use opt value will
//be wrong
atomic.AddUint64(&opt,1)
}
Continue…

wg.Done()
}()
}
wg.Wait()
fmt.Println("ops",opt)
}
Mutex
Mutex, mutual exclusion lock is a one way of accessing shared block of code
safely by multiple goroutines. Using mutex programmer can use traditional
locking way to handle concurrency issues like race conditions.
func mutexDemo(){
var state = make(map[int]int)
var mutex = &sync.Mutex{}

var readOps uint64


var writeOps uint64

for r:=0; r<100;r++{


go func() {
total :=0
for{
Continue…
key:=rand.Intn(5)
mutex.Lock()
total +=state[key]
mutex.Unlock()
atomic.AddUint64(&readOps,1)
time.Sleep(time.Millisecond)
}
}()
}
Continue…
for w:=0;w<10;w++{
go func() {
for {
key := rand.Intn(5)
val :=rand.Intn(100)
mutex.Lock()
state[key]=val
mutex.Unlock()
atomic.AddUint64(&writeOps,1)
time.Sleep(time.Millisecond)
}
}()
}
Continue…

time.Sleep(time.Second)
readOpsFinal:=atomic.LoadUint64(&readOps)
fmt.Println("readOps:",readOpsFinal)
writeOpsFinal:=atomic.LoadUint64(&writeOps)
fmt.Println("writeOps",writeOpsFinal)
fmt.Println("state",state)

}
RWmutex
This is an extension of mutex which introduce another two methods RLock and
RUnlock. This can be used to get more flexibility between read lock and write
lock. There are few important.
RLock is a shared read lock, so multiple threads can call RLock that means
multiple threads can reads at same time
If the mutex is read locked, a call to Lock is blocked. Which means if at least one
read lock is being called unable to write
If the mutex is write locked(with Lock) RLock will block.
If the reader counter is>0 and Lock is called, further calls to RLock will also block
until existing readers have released their locks, the writer has obtained his lock and
later release it
In a situation such that more number of reads occurring and less number of writing
it’s a good idea to use RWmutex instead of normal mutex.
Continue…
type mapLock struct {
lock sync.RWMutex
m map[int]string
}
var myMapLock = mapLock{
m:make(map[int]string),
}
func lockWithMap() {
go func() {
for i:=0;i<50;i++ {
writeLockWithMap(1)
}
}()
Continue…

Package go-lock is a Golang library implementing an effcient read-write lock with


the following built-in mechanism: - Mutex with timeout mechanism - Trylock -
No-starve read-write solution
type CASMutex
func NewCASMutex() *CASMutex
func (m *CASMutex) Lock()
func (m *CASMutex) RLock()
func (m *CASMutex) RLocker() sync.Locker
func (m *CASMutex) RTryLock() bool
func (m *CASMutex) RTryLockWithContext(ctx context.Context) bool
func (m *CASMutex) RTryLockWithTimeout(duration time.Duration) bool
Continue…

func (m *CASMutex) RUnlock()


 func (m *CASMutex) TryLock() bool
 func (m *CASMutex) TryLockWithContext(ctx context.Context) bool
 func (m *CASMutex) TryLockWithTimeout(duration time.Duration) bool
 func (m *CASMutex) Unlock()
 type ChanMutex
 func NewChanMutex() *ChanMutex
 func (m *ChanMutex) Lock()
 func (m *ChanMutex) TryLock() bool
 func (m *ChanMutex) TryLockWithContext(ctx context.Context) bool
 func (m *ChanMutex) TryLockWithTimeout(duration time.Duration) bool
 func (m *ChanMutex) Unlock()

You might also like