Declare a slice
var results []string
Append to a slice
results = append(results, result)
Append one slice to another
a := []int{1, 2}
b := []int{11, 22}
a = append(a, b...) // a == [1 2 11 22]
Split a string by space
words := strings.Fields(str)
Split a string by comma
words := strings.Split(str, ",")
Convert string to integer
i, err := strconv.Atoi("34")
Trim whitespace from a string
result := strings.TrimSpace(s)
Runes
Overview
# Convert string to rune slice
r := []rune("ABC€")
fmt.Println(r) // [65 66 67 8364]
fmt.Printf("%U\n", r) // [U+0041 U+0042 U+0043 U+20AC]
# Convert rune slice to string
s := string([]rune{'\u0041', '\u0042', '\u0043', '\u20AC', -1})
fmt.Println(s) // ABC€�
goroutines
- Unit of concurrency in go program
- Not OS Thread
- Not Green Thread - Thread managed by language runtime
- Coroutines - concurrent subroutines that are nonpreemptive (i.e. can't be interrupted)
- Go runtime observers runtime behavior of goroutines and automatically suspends them when they block and then resumes them when they are unblocked
- goroutines are implicitly concurrent constructs, with parallelism provided by Go runtime
- Go runtime schedules goroutines onto a M:N scheduler, which provides M Green threads mapped to N OS threads
- Go follows a fork-join model of concurrency
Simple go routines
func main() {
go sayHello()
}
func sayHello() {
fmt.Println("Hello")
}
go func() {
fmt.Println("Hello")
}()
go routines with join point implemented by Wait Group
var wg sync.WaitGroup
sayHello := func() {
defer wg.Done()
fmt.Println("Hello")
}
wg.Add(1)
go sayHello()
wg.Wait()
go routines "Close" around the lexical scope they are declared in, thus capturing variables
### World is printed out
var wg WaitGroup
greeting := "Hello"
sayHello := func() {
defer wg.Done()
greeting = "World"
}
wg.Add(1)
go sayHello()
wg.Wait()
fmt.Println(greeting)
Channels
- Channels are an important synchronisation primitive in golang. Channels are used to implement synchronisation by providing a communication mechanism among goroutines.
# Declare a bidirectional channel
var dataChannel chan interface{}
dataChannel = make(chan, interface{})
# Declare a read channel, that can only be read from
var readChannel <-chan interface{}
readChannel = make(<-chan, interface{})
# Declare a write channel, that can only be written to
var writeChannel chan<- interface{}
writeChannel = make(chan<-, interface{})
- Go implicitly converts bidirectional channel to unidirectional channel based on method signature
- Channels are typed
greetingChannel := make(chan, string)
go greet() {
greetingChannel <- "Hello"
}()
fmt.Println(<-greetingChannel)
- Reading from a write-only channel, writing to a read-only channel produced compile time errors
- Channels are blocking. Reading from an empty channel, writing to a full channel are blocking operations
- Blocking nature of channels can result in a deadlock if operations are not structured correctly
greetingChannel := make(chan, string)
go greet() {
if true {
return
}
greetingChannel <- "Hello"
}()
fmt.Println(<-greetingChannel)
- Reading a channel can optionally return a second return value - a boolean status that indicates if the value returned is from channel buffer of default nil value of a channel that has been closed.
greetingChannel := make(chan, string)
go greet() {
greetingChannel <- "Hello"
}()
greeting, ok := <-greetingChannel
range
keyword used in conjunction with for
loop supports Channels, and will break out when a channel has been closed
counterChannel := make(chan, int)
go count() {
defer close(counterChannel)
for i := 1; i <=5; i++ {
counterChannel <- i
}
}()
for count : range counterChannel {
fmt.Println(counter)
}
Barrier implementation with Channels
barrierChannel := make(chan, interface{})
var wg sync.WaitGroup
for i:=0; i<5; i++ {
wg.Add(1)
go work() {
defer(wg.Done())
<-barrierChannel
fmt.Println("Starting work")
}()
}
close(barrierChannel)
wg.Wait()
Safe channel programming constructs
- Channel ownership - Channel owner is a goroutine that is responsible for instantiating a channel, writing to it and closing the channel.
- Channel users have read only view of a channel.
channelOwner := func() <-chan int {
counterChannel := make(chan int)
go func() {
defer close(counterChannel)
for int i := 0; i < 5; i++ {
counterChannel <- i
}
}()
return counterChannel
}
counterChannel := channelOwner()
for count := range counterChannel {
fmt.Printf("Received %d\n", count)
}
fmt.Println("Done")
Context
Context