1. Ready, steady, GO!
Golang and Eco-system
Introduction/Overview
Author: Markus Schneider
Date: 10.03.2019
Version: Final-v1.3.0
License:
2. Why Go? 01
Some facts about Go 02
Important Aspects 03
Commands/Syntax Tour 04
Eco-System 05
Summary 06
Q&A/Discussion 07
Agenda
3. package main
import "fmt"
func main() {
fmt.Println("Name: Markus Schneider")
fmt.Println("Company/Business: @ruv_de/Insurance")
fmt.Println("Role: Senior IT Consultant/Cloud Tech.")
fmt.Println("Job: Monitoring/Product Owner")
fmt.Println("IT-Experience: ~20 years")
fmt.Println("Motivation: I like Go!")
fmt.Println("Twitter: @schneidermatic")
fmt.Println("GitHub: http://github.com/schneidermatic")
}
$> whoami
4. ●
Go is an open-source but backed up by a large corporation
●
Automatic memory management (garbage collection)
●
Strong focus on support for concurrency
●
Fast compilation and execution
●
Statically type, but feels like dynamically typed
●
Good cross-compiling (cross-platform) support
●
Go compiles to native machine code
●
Rapid development and growing community (Docker/Kubernetes)
Why Go?
6. ●
Go is a general-purpose language
●
Go is a structured programming language
●
Go is initially developed at Google in 2007
●
Go was announced in November 2009
●
Go is statically typed, compiled language
●
Go is an open source programming language
●
Go 1 was released in March 2012
●
Go is on position 18 according to the TIOBE Index in March 2019
●
Currently, Go 1.12 released in 25 February 2019
Some Facts about Go
7. ●
No type inheritance
●
No method or operator overloading
●
No support for pointer arithmetic
●
No support for Assertions
●
No Exceptions - instead use an error return type
●
No Generics support
●
Dependency management
– Go uses URL based dependency imports
– go get -u golang.org/x/tour
$> tour
– import github.com/somename/somelibrary
Important Aspects
9. Basic Syntax
package main
import "fmt"
func main() {
fmt.Println("Hello, 世界 ")
}
$> go run HelloWorld.go
Go natively handles Unicode, so it can process text in all the world’s languages
Output: Hello, 世界
11. Go keywords
●
Go has only 25 keywords, even less than german alphabet (26)!
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
12. Basic types
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // alias for uint8
rune // alias for int32
float32 float64
complex64 complex128
13. Packages
●
Every Go program is made up of package
●
Program start running in package main
●
Name is exported if it begins with a capital letter
package main
Import (
"fmt"
"math"
)
func main() {
fmt.Println(math.pi) //error
fmt.Println(math.Pi)
}
14. Functions
func add(x int, y int) int {
return x + y
}
func add(x, y int) int { // when args share the same type,
return x + y // type can be omitted for the first arg
}
func hello(x, y string) (string, string) {
return y, x // return multiple values
}
func hello(x, y string) (a, b string) {
a = x
b = y
return // name return value naked return
}
15. Variables
●
Use var statement declare a list of variables
var c, golang, java bool
func main() {
var i int
}
// variables with initializers
var i, j int = 1, 2
var c, golang, java = false, true, "no!"
●
Inside a functions, the := short assignment can be use in place of var
func main() {
c, golang, java := false, true, "no!"
}
16. Zero Values
●
Variables declared without initial value are given their zero values
0 for numeric types
false for boolean type
"" for string type
var i int
var f float64
var b bool
var s string
fmt.Printf("%v %v %v %qn", i, f, b, s)
// output: 0 0 false ""
17. Type Conversion
●
Go assignment between items of different type requires an explicit conversion
var i int = 42
var f float64 = float64(i)
var u unit = unit(f)
●
Constants are declared like variables, but with the const keyword
const Pi = 3.14
Constants
18. For loop
●
Go has only one looping construct, the for loop
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
// note: no () surrounding the three components; {} always required
for is Go’s while
sum := 1
for sum < 1000 {
sum += sum
}
19. If else
●
If can start with a short statement to execute before condition
if x := math.Sqrt(100); x < 10 {
fmt.Printf(“Square root of 100 is %vn”, x)
} else {
fmt.Printf(“Square root of 100 is %vn”, x)
}
// note: no () surrounding the condition; {} always required
21. Switch
●
Switch can start with a short statement to execute before condition
package main
import (
"fmt"
"runtime"
)
func main() {
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("Go runs on OS X.")
case "linux":
fmt.Println("Go runs on Linux.")
default:
fmt.Printf("Go runs on %s.", os)
}
}
22. Defer
●
A defer is used to ensure that a function calls is performed late in a program’s execution,
usually for purposes of cleanup. defer is often used where e.g. ensure and finally would
used in other languages
func main() {
f, err := os.Create("/tmp/defer.txt")
defer f.Close()
fmt.Fprintln(f, "Hello, 世界 ")
fmt.Println("counting down")
for i := 0; i < 10; i++ {
defer fmt.Print(i, " ")
}
}
// Output:
counting down
9 8 7 6 5 4 3 2 1 0
23. Pointer
●
Pointer is a variable whose value is the address of another variable
●
Ampersand (&) operator denotes an address in memory
●
Asterisk (*) operator denotes the pointer's underlying value
func main() {
i := 21
p := &i // store address of i in pointer variable p
fmt.Printf("Address stored in p variable: %pn", p) // print address
fmt.Printf("Value of i is: %vn", *p) // read i through the pointer
*p = 77 // set i through the pointer
fmt.Printf("New value of i is: %vn", i) // see the new value of i
}
// Output:
Address stored in p variable: 0x1040e0f8
Value of i is: 21
New value of i is: 77
24. Struct
●
struct is a collection of fields
●
struct fields are accessed using a dot
●
struct fields can be accessed through a struct pointer
type Person struct {
Firstname string
Lastname string
}
func main() {
x := Person{"Gordan","Gopher"}
y := &x
y.Firstname := "George"
fmt.Println("My name is %s %s",y.Firstname, y.Lastname)
}
// Output:
My name is George Gopher
25. Arrays & Slices
●
var a [10]int
●
Array has a fixed size.
●
Slice is a dynamically-size, flexible view of an array; var a []int
primes := [6]int{2, 3, 5, 7, 11, 13}
var s []int = primes[1:4]
fmt.Println(s) // output: [3 5 7]
●
Slice is like reference to array; it does not store any data
names := [4]string{"John", "Paul", "George", "Ringo"}
fmt.Println(names) // [John Paul George Ringo]
a := names[1:3]
fmt.Println(a) // [Paul George]
a[0] = "XXX"
fmt.Println(a) // [XXX George]
fmt.Println(names) // [John XXX George Ringo]
26. Make function
●
Slices can be created with the built-in make function; this is how you create
dynamically-sized array
func printSlice(s string, x []int) {
fmt.Printf("%s len=%d cap=%d %vn", s, len(x), cap(x), x)
}
func main() {
a := make([]int, 5) // len(a) = 5; length of a is 5
printSlice("a", a) // output: a len=5 cap=5 [0 0 0 0 0]
b := make([]int, 0, 5) // len(b) = 0, cap(b) = 5
printSlice("b", b) // output: b len=0 cap=5 []
}
27. Append function
●
Go provides a built-in append function
func main() {
var s []int
printSlice(s) // output: len=0 cap=0 []
s = append(s, 0) // append works on nil slices.
printSlice(s) // output: len=1 cap=2 [0]
s = append(s, 1) // The slice grows as needed.
printSlice(s) // output: len=2 cap=2 [0 1]
s = append(s, 2, 3, 4) // add more than one element at a time
printSlice(s) // output: len=5 cap=8 [0 1 2 3 4]
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %vn", len(s), cap(s), s)
}
28. Range
●
Range form the for loop iterates over a slice or map
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
for i, v := range pow {
fmt.Printf("2^%d = %dn", i, v)
}
// Output:
2^0 = 1
2^1 = 2
2^2 = 4
2^3 = 8
2^4 = 16
2^5 = 32
2^6 = 64
2^7 = 128
29. Map
●
make function returns a map of the given type, initialized and ready to use
m := make(map[string]int) // initialized map
m["Answer"] = 42 // insert element
fmt.Println("The value:", m["Answer"]) // output: The value: 42
m["Answer"] = 48 // update element
fmt.Println("The value:", m["Answer"]) // output: The value: 48
delete(m, "Answer”) // delete element
fmt.Println("The value:", m["Answer"]) // output: The value: 0
v, ok := m["Answer”] // If key is in map, ok is true
fmt.Println("The value:", v, "Present?", ok) // If not, ok is false
// output: The value: 0 Present? false
31. Methods
●
A method is a function with a special receiver argument
●
Receiver type must be defined in the same package as the method
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
func main() {
f := MyFloat(-21)
fmt.Println(f.Abs()) // Output: 21
}
32. Pointer receivers
●
Methods with pointer receivers can modify the value to which the receiver points
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func main() {
v := Vertex{3, 4}
fmt.Println(v.Abs()) // Output: 5
v.Scale(10)
fmt.Println(v.Abs()) // Output: 50
}
33. Interface
●
Interface type is defined as a set of method signatures
●
A type implements an interface by implementing its methods
●
There is no explicit declaration of intent, no "implements" keyword
type I interface {
M()
}
type T struct {
S string
}
func (t T) M() { // This method means type T implements the interface I
fmt.Println(t.S)
}
func main() {
var i I = T{"hello”}
i.M() // Output: hello
}
34. Empty interface
●
Interface type that specifies zero methods is known as the empty interface
●
An empty interface may hold values of any type
●
Ex: fmt.Print takes any number of arguments of type interface{}
func main() {
var i interface{}
describe(i) // Output: (<nil>, <nil>)
i = 42
describe(i) // Output: (42, int)
i = "hello"
describe(i) // Output: (hello, string)
}
func describe(i interface{}) {
fmt.Printf("(%v, %T)n", i, i)
}
35. Stringer
●
Stringer is defined by the fmt package
type Stringer interface {
String() string
}
●
Stringer is a type that can describe itself as a string
●
fmt package (and many others) look for this interface to print values
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}
func main() {
a := Person{"Arthur Dent", 42}
fmt.Println(a) // output: Arthur Dent (42 years)
}
36. Error
●
The error type is a built-in interface similar to fmt.Stringer
type error interface {
Error() string
}
type MyError struct {
When time.Time
What string
}
func (e *MyError) Error() string {
return fmt.Sprintf("at %v, %s", e.When, e.What)
}
func run() error {
return &MyError{ time.Now(), "it didn't work” }
}
func main() {
if err := run(); err != nil {
fmt.Println(err) // at 2017-03-08 23:00:00 +0700 ICT, it didn't work
}
}
37. Panic
●
A panic typically means something went unexpectedly wrong. Mostly we use it to fail fast on
errors that shouldn’t occur during normal operation, or that we aren’t prepared to handle
gracefully.
package main
import "os"
func main() {
// We'll use panic throughout this site to check for
// unexpected errors. This is the only program on the
// site designed to panic.
panic("a problem")
// A common use of panic is to abort if a function
// returns an error value that we don't know how to
// (or want to) handle. Here's an example of
// `panic`king if we get an unexpected error when creating a new file.
_, err := os.Create("/tmp/file")
if err != nil {
panic(err)
}
}
38. Goroutine
●
Goroutine is a lightweight thread managed by the Go runtime
●
Goroutines run in the same address space, so access to shared memory must be synchronized
●
One goroutine usually uses 4 - 5 KB of stack memory
●
Therefore, it's not hard to run thousands of goroutines on a single computer
func say(s string) { // Output:
for i := 0; i < 5; i++ { world
time.Sleep(100 * time.Millisecond) hello
fmt.Println(s) hello
} world
} world
hello
func main() { hello
go say("world”) world
say("hello") world
} hello
39. Channel
●
Channel is one of the features that make Golang unique
●
The purpose of using Channel is to transfer values in goroutines
ch <- v // Send v to channel ch
v := <-ch // Receive from ch, and assign value to v
●
Like maps and slices, channels must be created before use:
ch := make(chan int)
40. Channel: example
●
Sum the numbers in a slice, distributing the work between two goroutines.
●
Once both goroutines completed their computation, it calculates the final result
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // send sum to c
}
func main() {
s1 := []int{1, 2, 3}
s2 := []int{4, 5, 6}
c := make(chan int)
go sum(s1, c) // [1 2 3]
go sum(s2, c) // [4 5 6]
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y) // output: 15 6 21
}
Blank Identifier
52. https://kubernetes.io/
Kubernetes –
Is there anyone out
there who has not heard
of Kubernetes yet? ;)
Kubernetes –
Is there anyone out
there who has not heard
of Kubernetes yet? ;)
53. ●
Go excels in being simple and easy to understand
●
Go is a general purpose language and brightly adopted
●
Go is a compiled language and optimized for speed
●
Go has the ability for cross-compiling your application to run on a
different machine than the one used for development
●
Go compiler offers additional benefits like being able to check for errors,
easier deployment and the ability to optimize your code for efficiency
●
Go has strong support for concurrency
●
Go has a rich eco-system and a large community
Conclusion
●
Ease of deployment, strong concurrency and a simple syntax make
Go a great language to build fast, scalable applications
Summary
54. Thank you
… for your interest!
Q&A / Discussion
Kudos to the golang community for
information, icons and code samples