Devs@Home
Einführung in Go
Vorstellung
Frank Müller

Oldenburg

Baujahr 1965

Solution Engineer

Loodse GmbH

@themue
Go Erfahrung
• Artikel, Buch, Talks, Kolumne rund um Go
seit 2010

• Seit 2011 professionelle Nutzung

• Cloud Provisioning

• Microservices in der Logistik

• Ethereum Messaging

• Kubernetes Cluster Management

• OSS unter dem Label Tideland
Überblick
Kurzeinführung
• Go ist langweilig

• Go folgt keinem klaren Paradigma

• Go bietet keine esoterischen Features

• Go bietet nichts wirklich Neues

• Go ist nicht perfekt

• Go beinhaltet Stolpersteine
ABER
• Go ist einfach (Language Specification nur
eine HTML Seite)

• Go bringt eine umfangreiche Bibliothek mit
sich

• Go kompiliert sehr schnell in ein Binary

• Go beherrscht Cross-Compiling

• Go verfügt über Garbage Collection

• Go führt sehr schnell aus

• Go ist pragmatisch
Kurzeinführung
❝
It’s better to have a permanent income than to be
fascinating.
Oscar Wilde
Historie
Historie
• Start Ende 2007 aus Frust

• FAQ: "One had to choose either efficient
compilation, efficient execution, or ease of
programming; all three were not available in
the same mainstream language."

• Beginn der Entwicklung Mitte 2008

• Erste öffentliche Vorversion im November
2009

• Version 1.0 im März 2012
❝Go aims to combine the safety and performance of a
statically typed compiled language with the
expressiveness and convenience of a dynamically
typed interpreted language.
It also aims to be suitable for modern systems – large
scale – programming.
Rob Pike
Das Team
• Rob Pike

• Ken Thompson

• Robert Griesemer

• Russ Cox

• Ian Lance Taylor

• Und weitere ...
Keine Unbekannten
• Ken Thompson — Multics, Unix, B, Plan 9,
ed, UTF-8, etc. sowie Turing Award

• Rob Pike — Unix, Plan 9, Inferno, Limbo,
UTF-8, etc.

• Robert Griesemer — Strongtalk, Java
HotSpot VM, V8 JavaScript Engine
Fortschritt
• 2014 wurde der der Gopher das Maskottchen
von Go; entworfen von Renée French, der
Ehefrau von Rob Pike

• Alle 6 Monate erscheint ein neues Release

• Aktuell Version 1.14.1

• Versprechen der Sprachkompatibilität
gleicher Hauptversionen

• Go 2 in Diskussion
Werkzeuge
Drei Binaries
• go — Wichtigstes Werkzeug mit vielen
Subcommands

• gofmt — Einheitliche Formatierung der Go
Quellen

• godoc — Generierung von Dokumentation
aus Kommentaren
go Subcommands (Auszug)
• build — Compiling der Quellen

• fmt — Formattierung der Quellen

• get — Packages herunterladen und
installieren

• install — Compiling und Installation der
Quellen

• mod — Verwaltung von Modulen

• test — Durchführung der Unit Tests

• vet — Bericht über gängige Fehler
go mod Subcommands (Auszug)
• download — Download von Modulen in
lokalen Cache

• init — Initialisierung eines Moduls im
aktuellen Verzeichnis 

• tidy — Bereinigung der Abhängigkeiten

• vendor — Vendorize von Abhängigkeiten

• why — Erläuterung von Abhängigkeiten
Die Sprache Go
Orientierung in Packages
• Code immer in Packages

• Ein oder mehrere Dateien pro Package in
einem Verzeichnis

• Sonderrollen

• main wird zu ausführbarem Programm

• <name>_test wird zu Unit Test von
Package <name>

• Packages lassen sich hierarchisch schachteln
Package main
!// main wird zu Programm mit dem Namen des Verzeichnisses

!// oder einem per Argument bestimmten Namen.

package main

!// Einstieg in das Programm.

func main() {

println("Hello, World!")

}
Import von Packages
• Import direkt nach dem Package Statement

• Externe Packages mit Domain und Pfad

• Eigene Domains mit Code auf z.B. GitHub
sind via Meta Tags in einem lokalen HTML-
Dokument ebenfalls möglich

• Package-Name als Präfix für Namensräume

• Aliase bei Namensgleichheit möglich

• Export durch Großschreibung, sonst package
private
Verschiedene Importe
package info

import (

"fmt"

"github.com/moby/moby/volume"

myvolume "github.com/myname/myproject/volume"

)

func Info() string {

return fmt.Sprintf("name %v / size %v",

volume.DefaultDriverName, myvolume.DefaultSize())

}
Funktionen
• Schlüsselwort func

• Mit Namen, anonym oder als Methode
eigener Typen

• Beliebige Anzahl Parameter, letzter kann
variadisch sein

• Beliebige Anzahl Rückgabewerte ohne und
mit Namen

• Rückgabe mit Schlüsselwort return
Definition einer einfachen Funktion
!// Mul multipliziert f mit einer beliebigen Anzahl

!// Integer.

func Mul(f int, vs !!...int) int {

r !:= f

for _, v !:= range vs {

r *= v

}

return r

}
Funktion mit Ergebnis und Fehler
!// Div dividiert f ganzzahlig durch eine beliebige Anzahl 

!// Integer.

func Div(f int, vs !!...int) (int, error) {

r !:= f

for _, v !:= range vs {

if v !== 0 {

return 0, errors.New("division by zero")

}

r !/= v

}

return r, nil

}
Optionen als Funktionen 1/3
!// Server ist ein Typ mit privaten Feldern.

type Server struct {

port int

!!...

}

!// Option ist eine Funktion, die auf einem Server operiert.

type Option func(s *Server)
Optionen als Funktionen 2/3
!// Port liefert eine Option zum Setzen des Felds port

!// zurück.

func Port(port int) Option {

return func(s *Server) {

s.port = port

}

}
Optionen als Funktionen 3/3
!// New erzeugt einen Server. Optionen sind !!... optional. ;)

func New(opts !!...Option) *Server {

s !:= &Server{

port: 12345, !// Standardwert.

!!...

}

for _, opt !:= range opts {

opt(s)

}

return s

}
Typenlehre
Einfache Typen
• int / int8 / int16 / int32 / rune / int64

• uint / uint8 / byte / uint16 / uint32 / uint64

• float32 / float64

• complex64 / complex128

• bool

• string
Zusammengesetzte Typen
• Arrays und Slices

• Maps

• Structs

• Funktionen

• Interfaces

• Error

• Channel
Methoden und Interfaces
type StringProducer func() []string

func (sp StringProducer) Len() int {

return len(sp())

}

!// Sizer definiert in meinem Package, was ich von einem

!// Typ benötige.

type Sizer interface {

Len() int

}

func SizePrinter(sizer Sizer) { !!... }
Einbetten von Typen
type Honker interface {

Honk() string

}

!// Car bettet Honker ein, geht mit Structs und Interfaces.

type Car struct {

Honker

motor *Motor

!!...

}

myCar.Honk()
Flexibilität durch Interfaces
!// Handler in Package net/http definiert einen Handler für

!// Web Requests.

type Handler interface {

ServeHTTP(ResponseWriter, *Request)

}

!// ListenAndServe startet den Server mit einem Handler.

func ListenAndServe(addr string, handler Handler) error
Funktionstypen erlauben Methoden
!// HandlerFunc vereinfach den Handler zu nur einer Funktion.

type HandlerFunc func(ResponseWriter, *Request)

!// ServeHTTP implementiert den Handler und führt nur die

!// Handler-Funktion aus.

func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {

f(w, r)

}
Weitere Implementierungen
!// ServeMux verteilt auf Handler nach Pfaden.

type ServeMux struct {

!!... 

}

func (mux *ServeMux) Handle(pattern string, handler Handler) {

!!...

}

!// ServeHTTP implementiert Handler.

func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {

!!...

}
Vom einfachem Interface zu Lösungen
• Multiplexer für HTTP Methoden

• Multiplexer für Schachtelung bei RESTful
APIs

• Schachtelung für Trennung von
Authentisierung/Autorisierung via JSON Web
Tokens o.ä.
Variablen explizit und implizit
• Mit Deklaration via var oder mit Zuweisung
durch :=
• Typisierung explizit oder implizit

• var kennt beides, := ist immer implizit

• Zuweisung mit =
Unterschiedliche Zuweisungen
var s1 string !// Deklaration

s1 = "Hello" !// Zuweisung

var s2 string = "World" !// Explizit mit Zuweisung

var s3 = s1 + ", " + s2 !// Implizit mit Zuweisung

s4 ":= s3 + "!" !// Deklaration implizit mit

!// Zuweisung
Kontrolle behalten
Bedingungen
• Mit if oder switch für logische Bedingungen

• Mit select für Channel

• switch und select kennen default an
beliebiger Stelle

• break nicht notwendig

• switch verfügt über fallthrough für die
Ausführung der Folgebedingung
Verzweigung mit if
if x > y {

x, y = y, x

}

if myFunctionReturnsTrue() {

fmt.Println("Juchu!")

} else {

fmt.Println("Schade")

}
Verzweigung mit switch
switch x {

case 1, 2, 3:

fmt.Println("1 bis 3")

!// Verpönte Weiterverarbeitung!

fallthrough

case 4, 5, 6:

fmt.Println("4 bis 6")

default:

fmt.Println("Keine Ahnung")

}
Verzweigung mit Bedingungen
!// Abarbeitung von oben nach unten, aber default immer nur

!// wenn nichts passt.

switch {

case x < 0:

fmt.Println("Kleiner als 0")

default:

fmt.Println("Ha! Genau 0")

case x > 0:

fmt.Println("Größer als 0")

}
Channel-Verzweigung mit select
select {

case !<-ctx.Done()

return ctx.Err()

case job !:= !<-jobs:

if err !:= job(); err !!= nil {

log.Printf("job failed: %v", err)

}

case !<-time.Tick(5 * time.Second):

log.Printf("I'm waiting !!...")

}
Schleifen
• Schlüsselwort for

• Verschiedene Formen der Bedingungen

• Vorzeitige Fortsetzung über continue

• Vorzeitiges Verlassen über break

• Label für geschachtelte Schleifen

• Arrays, Slices, Maps und Channel können mit
range iteriert werden
Schleifen 1/2
for {

!!...

if shallLeave {

break

}

}

i !:= 0

for i < 2019 {

!!...

i!++

}
Schleifen 2/2
for i !:= 0; i < 2019; i!++ {

if i % 2 !== 0 {

continue

}

!!...

}

visitors !:= visitorsByWebinar("Devs@Home")

for i, visitor !:= range visitors {

fmt.Printf("Besucher %d ist %sn", i, visitor.Name)

}
Nebenläufigkeit
Nebenläufigkeit
• Leichtgewichtige Funktionen (Goroutinen) im
Thread Pool

• Schnelle Kontextwechsel

• Kommunikation über typisierte Channel

• Abfrage mehrerer Channel gleichzeitig über
select

• Start mit Schlüsselwort go

• Gibt keine Instanz oder ID zurück
❝In programming, concurrency is the composition of
independently executing processes, while parallelism
is the simultaneous execution of (possibly related)
computations.
Concurrency is about dealing with lots of things at
once. Parallelism is about doing lots of things at once.
Rob Pike
Muster
Typische Varianten von Goroutinen
• „Mach mal.“

• „Mach mal und bring mir dann das Ergebnis.“

• „Kümmere dich um alle meine Aufträge.“

• „Sei mein schlauer Kollege.“
Verarbeitungsschlangen
Step 1 Step 3Step2
Client / Server
Client
Client
Client
Server
Lastverteilung
Client
Client
Client
Dispatcher
Worker
Worker
Worker
Verarbeitung von Events
Client
Handler
Handler
Handler
Event
Server
Map / Reduce
Map Reduce
Map
Map
Reduce
Map
Reduce
Netze von Goroutinen
Goroutine Goroutine Goroutine Goroutine
Goroutine Goroutine Goroutine
Goroutine Goroutine
Server als Beispiel
Einfacher Taschenrechner
type Op func()

!// Calc ist ein Taschenrechner mit einem Wert als Zustand.

type Calc struct {

cancel context.CancelFunc

ops chan Op

value float64

}
Konstruktion des Rechners
func New(ctx cancel.Context) *Calc {

c !:= &Calc{

ops: make(chan Op, 1),

value: 0.0,

}

ctx, c.cancel = context.WithCancel(ctx)

go c.backend(ctx)

return c

}
Stoppen über den Context
func (c *Calc) Stop() {

c.cancel()

}
Versand von Funktion an Backend
func (c *Calc) Add(v float64) (r float64) {

wait !:= make(chan struct{})

c.ops !<- func() {

c.value += v

r = c.value

close(wait)

log.Printf("calc added %f, new value is %f", v, r)

}

!<-wait

return

}
Fehlerkontrolle des Eingabewerts
func (c *Calc) Div(v float64) (r float64, err error) {

if v "== 0 { return 0.0, errors.New("divide by zero") }

wait !:= make(chan struct{})

c.ops !<- func() {

c.value !/= v

r = c.value

close(wait)

log.Printf("calc divided %f, new value is %f", v, r)

}

!<-wait

return

}
Ausführung im Backend
func (c *Calc) backend(ctx context.Context) {

for {

select {

case !<-ctx.Done():

return

case op !:= !<-c.ops:

op()

}

}

}
Fallstricke
Volle Kanäle 1/5
Sender
Sender
Sender
Receiver
Volle Kanäle 2/5
• Nicht wie bei OOP überschneidender Zugriff

• Serialisierung eingehender Nachrichten

• Synchrone Zugriffe werden blockiert, Queues
laufen voll und blockieren ebenso
Volle Kanäle 3/5
• Last möglichst beim Aufrufer belassen

• Zentrale Goroutine zur Datenverwaltung

• Weitere Last und Daten auf Arbeits-
Goroutinen verteilen

• Mutex / RWMutex in Go können helfen
Volle Kanäle 4/5
Client Server
DoThis()
Data()
API
return data
SetData()
Work()
Client Goroutine
Volle Kanäle 5/5
Client
B
Client
A
Worker
3
Worker
2
Worker
1
Server
DoThis() DoThis()
return result
Race Conditions 1/4
Client
A
Client
B
Server
Amount()
Amount()
SetAmount()
SetAmount()
return
amount
return
amount
Race Conditions 2/4
• Überlagerndes Lesen und Setzen

• Update durch Delta mit Rückgabe des neuen
Wertes

• Alternativ Rückgabe des Wertes mit Handle
für Aktualisierung
Race Conditions 3/4
Client
A
Client
B
Server
UpdateAmountBy()
UpdateAmountBy()
return
new amount
return
new amount
Race Conditions 4/4
Client
A
Client
B
Server
AmountHandle()
AmountHandle()
SetAmountWithHandle()
return amount
and handle
return
error "no handle"
Nicht-atomare Veränderungen 1/3
Client
A
Server
Client
B
SetStreet()
SetCity() Street()
City()
Nicht-atomare Veränderungen 2/3
• Auslöser sind zu granuläre Nachrichten und
nicht eingehaltene Protokolle

• Zusammenhängende Daten gleichzeitig
ändern beziehungsweise auslesen
Nicht-atomare Veränderungen 3/3
Client
A
Server
Client
B
SetAddress() Address()
Blockaden durch Cycles 1/3
Goroutine A Goroutine B
Goroutine C
Foo()
Bar()
Yadda()
return
return
Blockaden durch Cycles 2/3
• Auslöser sind synchrone Abfragen

• Timeouts zeigen Blockaden auf, vermeiden
jedoch nicht den Fehler

• Bei zwingender Abhängigkeit Design auf
Basis asynchroner Kommunikation

• Zustandsänderungen in den Prozessen
müssen dies berücksichtigen
Blockaden durch Cycles 3/3
Goroutine A Goroutine B
Goroutine C
Foo(1)
Bar(1)
Yadda(1)
SetBar(1)
SetFoo(1)
SetYadda(1)
Weiteres
Aufschieben
• Funktionen können im Ablauf mit defer
gestapelt werden

• Werden rückwärts beim Verlassen der
umgebenden Funktion ausgeführt

• Praktisch für Aufräumarbeiten, zum Beispiel
Schließen geöffneter Dateien
Mehrere gestapelte Aufräumer
file, err !:= ioutil.TempFile("/tmp", "webinar-*")

if err !!= nil {

return fmt.Errorf("failed to open temp file: %v", err)

}

defer file.Close()

writer !:= bufio.NewWriter(file)

defer writer.Flush()

writer.WriteString("Webinar Devs@Homen")

writer.WriteString("Einführung in Gon")
Fehlerbehandlung
• Keine Exceptions

• Fehlertyp error als letzter Rückgabewert

• Interface mit Methode Error() string

• Helfer im Package errors

• panic() für echte Ausnahmesituationen

• Kann mit recover() aufgefangen werden
Paniken auffangen
func CanBreakHard(x int) (err error) {

defer func() {

if r !:= recover(); r !!= nil {

err = fmt.Errorf("panic: %v", r)

}

}()

!!...

if veryBadCondition {

panic("have a very, yes, very, very bad condition")

}

return nil

}
Bibliothek
Daten
• Archivierung (tar, zip)

• Komprimierung (bzip2, flate, gzip, lzw, zlib)

• Encoding (ASN.1, CSV, JSON, XML)

• Strings, Text, Konvertierung, reguläre
Ausdrücke

• Text Templates

• Time

• Unicode
Netz
• Crypto (AES, Cipher, ECDSA, HMAC, RSA,
SHA512, TLS)

• Netzwerk

• HTTP Client und Server

• HTML Templates

• JSON-RPC

• SMTP
Und vieles mehr ...
• I/O

• SQL Datenbanken

• Synchronisation (Mutex, Once, WaitGroup),
Context

• Images

• Reflection

• Unit Tests
Zusammenfassung
Paradigmenmix ohne Overload
• Sequentielle Abfolge von Anweisungen ➟
imperativ

• Funktionstypen, Closures ➟ funktional

• Methoden, Interfaces, Komposition ➟ objekt-
orientiert

• Goroutinen, Channels ➟ nebenläufig
Fast wie Scripting
• Einfache Syntax

• Leichtgewichtiges Typenmodell

• Wenige Schlüsselworte

• Schnelle Kompilation erlaubt schnelle Tests

• Aber: Manchmal mehrere Lösungswege
möglich

• Nutzung etablierter Konventionen hilft
Einfache Nebenläufigkeit
• Prinzipiell nur Funktionen

• Flexible Kommunikation

• Weitere Hilfen zur Synchronisation

• Aber: Kein Schutz vor gleichzeitigem Zugriff
auf Variablen

• Aber: Kein Schutz vor Locks und Races

• Tools helfen, ansonsten Verantwortung des
Entwicklers
Vielen Dank. Und nun Q&A ...

Devs@Home - Einführung in Go

  • 1.
  • 2.
  • 3.
    Go Erfahrung • Artikel,Buch, Talks, Kolumne rund um Go seit 2010 • Seit 2011 professionelle Nutzung • Cloud Provisioning • Microservices in der Logistik • Ethereum Messaging • Kubernetes Cluster Management • OSS unter dem Label Tideland
  • 4.
  • 5.
    Kurzeinführung • Go istlangweilig • Go folgt keinem klaren Paradigma • Go bietet keine esoterischen Features • Go bietet nichts wirklich Neues • Go ist nicht perfekt • Go beinhaltet Stolpersteine
  • 6.
    ABER • Go isteinfach (Language Specification nur eine HTML Seite) • Go bringt eine umfangreiche Bibliothek mit sich • Go kompiliert sehr schnell in ein Binary • Go beherrscht Cross-Compiling • Go verfügt über Garbage Collection • Go führt sehr schnell aus • Go ist pragmatisch Kurzeinführung
  • 7.
    ❝ It’s better tohave a permanent income than to be fascinating. Oscar Wilde
  • 8.
  • 9.
    Historie • Start Ende2007 aus Frust • FAQ: "One had to choose either efficient compilation, efficient execution, or ease of programming; all three were not available in the same mainstream language." • Beginn der Entwicklung Mitte 2008 • Erste öffentliche Vorversion im November 2009 • Version 1.0 im März 2012
  • 10.
    ❝Go aims tocombine the safety and performance of a statically typed compiled language with the expressiveness and convenience of a dynamically typed interpreted language. It also aims to be suitable for modern systems – large scale – programming. Rob Pike
  • 11.
    Das Team • RobPike • Ken Thompson • Robert Griesemer • Russ Cox • Ian Lance Taylor • Und weitere ...
  • 12.
    Keine Unbekannten • KenThompson — Multics, Unix, B, Plan 9, ed, UTF-8, etc. sowie Turing Award • Rob Pike — Unix, Plan 9, Inferno, Limbo, UTF-8, etc. • Robert Griesemer — Strongtalk, Java HotSpot VM, V8 JavaScript Engine
  • 13.
    Fortschritt • 2014 wurdeder der Gopher das Maskottchen von Go; entworfen von Renée French, der Ehefrau von Rob Pike • Alle 6 Monate erscheint ein neues Release • Aktuell Version 1.14.1 • Versprechen der Sprachkompatibilität gleicher Hauptversionen • Go 2 in Diskussion
  • 14.
  • 15.
    Drei Binaries • go— Wichtigstes Werkzeug mit vielen Subcommands • gofmt — Einheitliche Formatierung der Go Quellen • godoc — Generierung von Dokumentation aus Kommentaren
  • 16.
    go Subcommands (Auszug) •build — Compiling der Quellen • fmt — Formattierung der Quellen • get — Packages herunterladen und installieren • install — Compiling und Installation der Quellen • mod — Verwaltung von Modulen • test — Durchführung der Unit Tests • vet — Bericht über gängige Fehler
  • 17.
    go mod Subcommands(Auszug) • download — Download von Modulen in lokalen Cache • init — Initialisierung eines Moduls im aktuellen Verzeichnis • tidy — Bereinigung der Abhängigkeiten • vendor — Vendorize von Abhängigkeiten • why — Erläuterung von Abhängigkeiten
  • 18.
  • 19.
    Orientierung in Packages •Code immer in Packages • Ein oder mehrere Dateien pro Package in einem Verzeichnis • Sonderrollen • main wird zu ausführbarem Programm • <name>_test wird zu Unit Test von Package <name> • Packages lassen sich hierarchisch schachteln
  • 20.
    Package main !// mainwird zu Programm mit dem Namen des Verzeichnisses !// oder einem per Argument bestimmten Namen. package main !// Einstieg in das Programm. func main() { println("Hello, World!") }
  • 21.
    Import von Packages •Import direkt nach dem Package Statement • Externe Packages mit Domain und Pfad • Eigene Domains mit Code auf z.B. GitHub sind via Meta Tags in einem lokalen HTML- Dokument ebenfalls möglich • Package-Name als Präfix für Namensräume • Aliase bei Namensgleichheit möglich • Export durch Großschreibung, sonst package private
  • 22.
    Verschiedene Importe package info import( "fmt" "github.com/moby/moby/volume" myvolume "github.com/myname/myproject/volume" ) func Info() string { return fmt.Sprintf("name %v / size %v", volume.DefaultDriverName, myvolume.DefaultSize()) }
  • 23.
    Funktionen • Schlüsselwort func •Mit Namen, anonym oder als Methode eigener Typen • Beliebige Anzahl Parameter, letzter kann variadisch sein • Beliebige Anzahl Rückgabewerte ohne und mit Namen • Rückgabe mit Schlüsselwort return
  • 24.
    Definition einer einfachenFunktion !// Mul multipliziert f mit einer beliebigen Anzahl !// Integer. func Mul(f int, vs !!...int) int { r !:= f for _, v !:= range vs { r *= v } return r }
  • 25.
    Funktion mit Ergebnisund Fehler !// Div dividiert f ganzzahlig durch eine beliebige Anzahl !// Integer. func Div(f int, vs !!...int) (int, error) { r !:= f for _, v !:= range vs { if v !== 0 { return 0, errors.New("division by zero") } r !/= v } return r, nil }
  • 26.
    Optionen als Funktionen1/3 !// Server ist ein Typ mit privaten Feldern. type Server struct { port int !!... } !// Option ist eine Funktion, die auf einem Server operiert. type Option func(s *Server)
  • 27.
    Optionen als Funktionen2/3 !// Port liefert eine Option zum Setzen des Felds port !// zurück. func Port(port int) Option { return func(s *Server) { s.port = port } }
  • 28.
    Optionen als Funktionen3/3 !// New erzeugt einen Server. Optionen sind !!... optional. ;) func New(opts !!...Option) *Server { s !:= &Server{ port: 12345, !// Standardwert. !!... } for _, opt !:= range opts { opt(s) } return s }
  • 29.
  • 30.
    Einfache Typen • int/ int8 / int16 / int32 / rune / int64 • uint / uint8 / byte / uint16 / uint32 / uint64 • float32 / float64 • complex64 / complex128 • bool • string
  • 31.
    Zusammengesetzte Typen • Arraysund Slices • Maps • Structs • Funktionen • Interfaces • Error • Channel
  • 32.
    Methoden und Interfaces typeStringProducer func() []string func (sp StringProducer) Len() int { return len(sp()) } !// Sizer definiert in meinem Package, was ich von einem !// Typ benötige. type Sizer interface { Len() int } func SizePrinter(sizer Sizer) { !!... }
  • 33.
    Einbetten von Typen typeHonker interface { Honk() string } !// Car bettet Honker ein, geht mit Structs und Interfaces. type Car struct { Honker motor *Motor !!... } myCar.Honk()
  • 34.
    Flexibilität durch Interfaces !//Handler in Package net/http definiert einen Handler für !// Web Requests. type Handler interface { ServeHTTP(ResponseWriter, *Request) } !// ListenAndServe startet den Server mit einem Handler. func ListenAndServe(addr string, handler Handler) error
  • 35.
    Funktionstypen erlauben Methoden !//HandlerFunc vereinfach den Handler zu nur einer Funktion. type HandlerFunc func(ResponseWriter, *Request) !// ServeHTTP implementiert den Handler und führt nur die !// Handler-Funktion aus. func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r) }
  • 36.
    Weitere Implementierungen !// ServeMuxverteilt auf Handler nach Pfaden. type ServeMux struct { !!... } func (mux *ServeMux) Handle(pattern string, handler Handler) { !!... } !// ServeHTTP implementiert Handler. func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { !!... }
  • 37.
    Vom einfachem Interfacezu Lösungen • Multiplexer für HTTP Methoden • Multiplexer für Schachtelung bei RESTful APIs • Schachtelung für Trennung von Authentisierung/Autorisierung via JSON Web Tokens o.ä.
  • 38.
    Variablen explizit undimplizit • Mit Deklaration via var oder mit Zuweisung durch := • Typisierung explizit oder implizit • var kennt beides, := ist immer implizit • Zuweisung mit =
  • 39.
    Unterschiedliche Zuweisungen var s1string !// Deklaration s1 = "Hello" !// Zuweisung var s2 string = "World" !// Explizit mit Zuweisung var s3 = s1 + ", " + s2 !// Implizit mit Zuweisung s4 ":= s3 + "!" !// Deklaration implizit mit !// Zuweisung
  • 40.
  • 41.
    Bedingungen • Mit ifoder switch für logische Bedingungen • Mit select für Channel • switch und select kennen default an beliebiger Stelle • break nicht notwendig • switch verfügt über fallthrough für die Ausführung der Folgebedingung
  • 42.
    Verzweigung mit if ifx > y { x, y = y, x } if myFunctionReturnsTrue() { fmt.Println("Juchu!") } else { fmt.Println("Schade") }
  • 43.
    Verzweigung mit switch switchx { case 1, 2, 3: fmt.Println("1 bis 3") !// Verpönte Weiterverarbeitung! fallthrough case 4, 5, 6: fmt.Println("4 bis 6") default: fmt.Println("Keine Ahnung") }
  • 44.
    Verzweigung mit Bedingungen !//Abarbeitung von oben nach unten, aber default immer nur !// wenn nichts passt. switch { case x < 0: fmt.Println("Kleiner als 0") default: fmt.Println("Ha! Genau 0") case x > 0: fmt.Println("Größer als 0") }
  • 45.
    Channel-Verzweigung mit select select{ case !<-ctx.Done() return ctx.Err() case job !:= !<-jobs: if err !:= job(); err !!= nil { log.Printf("job failed: %v", err) } case !<-time.Tick(5 * time.Second): log.Printf("I'm waiting !!...") }
  • 46.
    Schleifen • Schlüsselwort for •Verschiedene Formen der Bedingungen • Vorzeitige Fortsetzung über continue • Vorzeitiges Verlassen über break • Label für geschachtelte Schleifen • Arrays, Slices, Maps und Channel können mit range iteriert werden
  • 47.
    Schleifen 1/2 for { !!... ifshallLeave { break } } i !:= 0 for i < 2019 { !!... i!++ }
  • 48.
    Schleifen 2/2 for i!:= 0; i < 2019; i!++ { if i % 2 !== 0 { continue } !!... } visitors !:= visitorsByWebinar("Devs@Home") for i, visitor !:= range visitors { fmt.Printf("Besucher %d ist %sn", i, visitor.Name) }
  • 49.
  • 50.
    Nebenläufigkeit • Leichtgewichtige Funktionen(Goroutinen) im Thread Pool • Schnelle Kontextwechsel • Kommunikation über typisierte Channel • Abfrage mehrerer Channel gleichzeitig über select • Start mit Schlüsselwort go • Gibt keine Instanz oder ID zurück
  • 51.
    ❝In programming, concurrencyis the composition of independently executing processes, while parallelism is the simultaneous execution of (possibly related) computations. Concurrency is about dealing with lots of things at once. Parallelism is about doing lots of things at once. Rob Pike
  • 52.
  • 53.
    Typische Varianten vonGoroutinen • „Mach mal.“ • „Mach mal und bring mir dann das Ergebnis.“ • „Kümmere dich um alle meine Aufträge.“ • „Sei mein schlauer Kollege.“
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
    Map / Reduce MapReduce Map Map Reduce Map Reduce
  • 59.
    Netze von Goroutinen GoroutineGoroutine Goroutine Goroutine Goroutine Goroutine Goroutine Goroutine Goroutine
  • 60.
  • 61.
    Einfacher Taschenrechner type Opfunc() !// Calc ist ein Taschenrechner mit einem Wert als Zustand. type Calc struct { cancel context.CancelFunc ops chan Op value float64 }
  • 62.
    Konstruktion des Rechners funcNew(ctx cancel.Context) *Calc { c !:= &Calc{ ops: make(chan Op, 1), value: 0.0, } ctx, c.cancel = context.WithCancel(ctx) go c.backend(ctx) return c }
  • 63.
    Stoppen über denContext func (c *Calc) Stop() { c.cancel() }
  • 64.
    Versand von Funktionan Backend func (c *Calc) Add(v float64) (r float64) { wait !:= make(chan struct{}) c.ops !<- func() { c.value += v r = c.value close(wait) log.Printf("calc added %f, new value is %f", v, r) } !<-wait return }
  • 65.
    Fehlerkontrolle des Eingabewerts func(c *Calc) Div(v float64) (r float64, err error) { if v "== 0 { return 0.0, errors.New("divide by zero") } wait !:= make(chan struct{}) c.ops !<- func() { c.value !/= v r = c.value close(wait) log.Printf("calc divided %f, new value is %f", v, r) } !<-wait return }
  • 66.
    Ausführung im Backend func(c *Calc) backend(ctx context.Context) { for { select { case !<-ctx.Done(): return case op !:= !<-c.ops: op() } } }
  • 67.
  • 68.
  • 69.
    Volle Kanäle 2/5 •Nicht wie bei OOP überschneidender Zugriff • Serialisierung eingehender Nachrichten • Synchrone Zugriffe werden blockiert, Queues laufen voll und blockieren ebenso
  • 70.
    Volle Kanäle 3/5 •Last möglichst beim Aufrufer belassen • Zentrale Goroutine zur Datenverwaltung • Weitere Last und Daten auf Arbeits- Goroutinen verteilen • Mutex / RWMutex in Go können helfen
  • 71.
    Volle Kanäle 4/5 ClientServer DoThis() Data() API return data SetData() Work() Client Goroutine
  • 72.
  • 73.
  • 74.
    Race Conditions 2/4 •Überlagerndes Lesen und Setzen • Update durch Delta mit Rückgabe des neuen Wertes • Alternativ Rückgabe des Wertes mit Handle für Aktualisierung
  • 75.
  • 76.
  • 77.
  • 78.
    Nicht-atomare Veränderungen 2/3 •Auslöser sind zu granuläre Nachrichten und nicht eingehaltene Protokolle • Zusammenhängende Daten gleichzeitig ändern beziehungsweise auslesen
  • 79.
  • 80.
    Blockaden durch Cycles1/3 Goroutine A Goroutine B Goroutine C Foo() Bar() Yadda() return return
  • 81.
    Blockaden durch Cycles2/3 • Auslöser sind synchrone Abfragen • Timeouts zeigen Blockaden auf, vermeiden jedoch nicht den Fehler • Bei zwingender Abhängigkeit Design auf Basis asynchroner Kommunikation • Zustandsänderungen in den Prozessen müssen dies berücksichtigen
  • 82.
    Blockaden durch Cycles3/3 Goroutine A Goroutine B Goroutine C Foo(1) Bar(1) Yadda(1) SetBar(1) SetFoo(1) SetYadda(1)
  • 83.
  • 84.
    Aufschieben • Funktionen könnenim Ablauf mit defer gestapelt werden • Werden rückwärts beim Verlassen der umgebenden Funktion ausgeführt • Praktisch für Aufräumarbeiten, zum Beispiel Schließen geöffneter Dateien
  • 85.
    Mehrere gestapelte Aufräumer file,err !:= ioutil.TempFile("/tmp", "webinar-*") if err !!= nil { return fmt.Errorf("failed to open temp file: %v", err) } defer file.Close() writer !:= bufio.NewWriter(file) defer writer.Flush() writer.WriteString("Webinar Devs@Homen") writer.WriteString("Einführung in Gon")
  • 86.
    Fehlerbehandlung • Keine Exceptions •Fehlertyp error als letzter Rückgabewert • Interface mit Methode Error() string • Helfer im Package errors • panic() für echte Ausnahmesituationen • Kann mit recover() aufgefangen werden
  • 87.
    Paniken auffangen func CanBreakHard(xint) (err error) { defer func() { if r !:= recover(); r !!= nil { err = fmt.Errorf("panic: %v", r) } }() !!... if veryBadCondition { panic("have a very, yes, very, very bad condition") } return nil }
  • 88.
  • 89.
    Daten • Archivierung (tar,zip) • Komprimierung (bzip2, flate, gzip, lzw, zlib) • Encoding (ASN.1, CSV, JSON, XML) • Strings, Text, Konvertierung, reguläre Ausdrücke • Text Templates • Time • Unicode
  • 90.
    Netz • Crypto (AES,Cipher, ECDSA, HMAC, RSA, SHA512, TLS) • Netzwerk • HTTP Client und Server • HTML Templates • JSON-RPC • SMTP
  • 91.
    Und vieles mehr... • I/O • SQL Datenbanken • Synchronisation (Mutex, Once, WaitGroup), Context • Images • Reflection • Unit Tests
  • 92.
  • 93.
    Paradigmenmix ohne Overload •Sequentielle Abfolge von Anweisungen ➟ imperativ • Funktionstypen, Closures ➟ funktional • Methoden, Interfaces, Komposition ➟ objekt- orientiert • Goroutinen, Channels ➟ nebenläufig
  • 94.
    Fast wie Scripting •Einfache Syntax • Leichtgewichtiges Typenmodell • Wenige Schlüsselworte • Schnelle Kompilation erlaubt schnelle Tests • Aber: Manchmal mehrere Lösungswege möglich • Nutzung etablierter Konventionen hilft
  • 95.
    Einfache Nebenläufigkeit • Prinzipiellnur Funktionen • Flexible Kommunikation • Weitere Hilfen zur Synchronisation • Aber: Kein Schutz vor gleichzeitigem Zugriff auf Variablen • Aber: Kein Schutz vor Locks und Races • Tools helfen, ansonsten Verantwortung des Entwicklers
  • 96.
    Vielen Dank. Undnun Q&A ...