Benutzer-Werkzeuge

Webseiten-Werkzeuge


go_lernen

Go lernen

go1.22.2 / Ubuntu 24.04.3 LTS

Einleitung

Installation
> apt install golang-go
> go version
go version go1.22.2 linux/amd64
Hallo Welt
> vim hallo_gopher.go
package main
import (
        "fmt"
)
func main() {
        fmt.Println("Hallo Gopher!")
}
 
> go build hallo_gopher.go
> ./hallo_gopher
Hallo Gopher!

Das Erste Go-Projekt

Erstes Go-Projekt
> vim main.go
package main
import (
        "fmt"
)
func main() {
        fmt.Println("Hallo Go-Projekt!")
}
 
> go build main.go
> ./main 
Hallo Go-Projekt!
Hilfe
> go help build | less
Kode formatieren
> go fmt main.go
Dokumentation
> go doc fmt.Println
package fmt // import "fmt"
 
func Println(a ...any) (n int, err error)
    Println formats using the default formats for its operands and writes to
    standard output. Spaces are always added between operands and a newline
    is appended. It returns the number of bytes written and any write error

Die Datentypen in Go

  • Einfache Datentypen
    • String, für Zeichenketten
      • string in UTF-8-Kodierung
    • Boolean, für boolesche Wahrheitswerte
      • bool: true oder false
    • Zahlen, für von Integer bis Gleitkomma
      • int32
      • int64
      • float32
      • float64
    • komplexe Zahlen…
  • Zusammengesetzte Datentypen
    • Array, Sequenz mehrerer Elemente mit fixer Länge
    • Slice, Sequenz mehrerer Elemente mit variabler Länge
    • Map, Wörterbuch, das Schlüssel auf einen Wert abbildet

Variablen und Konstanten

Variablen
...
 
func main() {
        // Deklaration und Zuweisung in langer Form
        var s1 string = "eine Zeichenkette"
        var i1 int = 123
        var b1 bool = true
 
        fmt.Println(s1, i1, b1)
}
Package-Variable
...
 
// Diese Variable ist im ganzen Package verwendbar
var aPackageVar string = "eine globale Variable"
 
func main() {
        fmt.Println("Hallo Go-Projekt!")
}
Konstanten
package main
 
import (
        "fmt"
)
 
// Diese Konstante ist im ganzen Package verwendbar
const aPackageKons = "eine globale Konstante"
 
func main() {
        const k1 = "eine Zeichenkette"
        const k2 = 123 
 
        fmt.Println(k1, k2, k2+k2)
        fmt.Println(aPackageKons)
}

Arrays und Slices

Arrays und Slices sind Sequenzen mehrerer Elemente.

Arrays haben eine feste Länge.

Slices haben eine variable Länge, es entspricht einer "Liste" in C++ oder Java.

Array
package main
 
import (
        "fmt"
)
 
func main() {
        // Array (mit 2 Elementen) initialisieren und füllen
        array01 := [2]string{"Element1", "Element2"}
 
        fmt.Println("unverändert", array01)
 
        // ein Element im Array ändern, das erste Element hat den Index "0"
        array01[1] = "Fritz"
 
        fmt.Println("verändert", array01)
}
Slice
package main
 
import (
        "fmt"
)
 
func main() {
        // Slice mit make initialisieren
        slice01 := make ([]string, 2)
        slice01[0] = "Anita"
        slice01[1] = "Rom"
 
        fmt.Println(slice01)
 
        // Slice mit Werten initialisieren
        slice02 := []string{"Otto", "Hamburg"}
 
        fmt.Println(slice02)
 
        // Slice erweitern
        slice02 = append(slice02, "Bär", "Berlin")
 
        fmt.Println(slice02)
}

Maps für Schlüssel/Werte-Paare

Map
package main
 
import (
        "fmt"
)
 
func main() {
        // Map mit make initialisieren
        var map01 = make (map[string]int)
        map01["Anita"] = 23
        map01["Berta"] = 32
 
        fmt.Println(map01)
 
        // Map mit Werten initialisieren
        var map02 = map[string]int{"Papa": 54, "Mama": 45} 
 
        fmt.Println(map02)
 
        // Wert zu einem Schlüssel abrufen
        fmt.Println("Alter von Papa:", map02["Papa"])
}

Structs mit Feldern nutzen und definieren

In Go können mehrere Werte zu Strukturen ("Structs") zusammengefasst werden.

Mit Structs können Sie Daten kapseln, und das ganz ohne Objektorientierung.

Ein Struct ist ein einfacher Datenkontainer mit Feldern.

Struct
package main
 
import (
        "fmt"
)
 
type Struktur01 struct {
        Name string    // mit großem Anfangsbuchstaben ist es ein öffentliches Feld
        alter int      // mit kleinem Anfangsbuchstaben ist es ein privates Feld
}
 
// Struct einbinden
type Struktur02 struct {
        Struktur01     // das Struct "Struktur02" hat nun alle Felder, die das Struct "Struktur01" hat und es können zusätzliche hinzugefügt werden
        passwort string
}
 
func main() {
        // normales Struct
        c := Struktur01{Name: "Alfred Nobel", alter: 63} 
 
        fmt.Println(c)
 
        // ein Struct in ein anderes Struct einbinden
        d := Struktur02{passwort: "geheim"}
        d.Name = "Drachentöter"
 
        fmt.Println(d)
 
        // leeres Struct; es werden die initialen Werte ("0" und "leer") der Felder in Struktur01 ausgegeben
        var leereStruktur Struktur01
        fmt.Println(leereStruktur)
}

Pointer

pointer.go
package main
 
import (
        "fmt"
)
 
type Struktur01 struct {
        Name string    // mit großem Anfangsbuchstaben ist es ein öffentliches Feld
        alter int      // mit kleinem Anfangsbuchstaben ist es ein privates Feld
}
 
func main() {
        // normales Struct
        c := Struktur01{Name: "Alfred Nobel", alter: 63} 
 
        // Pointer p auf Struct c
        var p *Struktur01 = &c
 
        // Pointer mit * auflösen und Wert zuweisen (Überschreiben)
        (*p).Name = "Gorilla"
 
        fmt.Println("c:", c)
        fmt.Println("Pointer auf c:", p)
}

Der leere Wert nil

nil.go
package main
 
import (
        "fmt"
)
 
type Struktur01 struct {
        Name string    // mit großem Anfangsbuchstaben ist es ein öffentliches Feld
        alter int      // mit kleinem Anfangsbuchstaben ist es ein privates Feld
}
 
func main() {
        // Pointer ist nil
        var p *Struktur01
 
        // prüfen ob der Pointer p nil ist
        fmt.Println("Pointer p ist nil:", p == nil)
 
        // Slice ist nil
        var s []float64
        fmt.Println("Slice s ist nil:", s == nil)
 
        // Map ist nil
        var m map[string]float64
        fmt.Println("Map m ist nil:", m == nil)
}

Fehler

In Go gibt es keine Spezialbehandlung für Fehler. In Go sind Fehler Werte wie Strings, Integer oder Struts.

Fehler.go
package main
 
import (
        "fmt"
)
 
func main() {
        // Error
        err := fmt.Errorf("Benutzer %v wurde nicht gefunden", "Spenzer")
        fmt.Println("Error err:", err)
}

In Go gibt es für Fehler den Typ "error". "error" ist ein gewöhnlicher Go-Datentyp, jedoch mit besonderer Bedeutung.

Den Kontrollfluss strukturieren

Kontrollstruktur if/else

kontrolle_if.go
package main
 
import (
        "fmt"
)
 
func main() {
        // if
        zweifler := "gehen"
        if zweifler != "laufen" {
                fmt.Println("Du sollst jetzt nicht laufen.")
        }
 
        // if/else
        geschwindigkeit := 100
        if geschwindigkeit < 120 {
                fmt.Println("Du bist zu langsam.")
        } else if geschwindigkeit == 120 {
                fmt.Println("Die Geschwindigkeit stimmt.")
        } else {
                fmt.Println("Du bist zu schnell.")
        }
}

Kontrollstruktur Switch

kontrolle_switch.go
package main
 
import (
        "fmt"
        "time"
)
 
func main() {
        // Switch mit Ausdruck
        geschwindigkeit := 100 
        switch {
        case geschwindigkeit < 120:
                fmt.Println("Du bist zu langsam.")
        case geschwindigkeit == 120:
                fmt.Println("Die Geschwindigkeit stimmt.")
        default:
                fmt.Println("Du bist zu schnell.")
        }
 
        // Switch über Typ
        switch time.Now().Weekday() {
        case time.Saturday:
                fmt.Println("Es ist Sonnabend.")
        case time.Sunday:
                fmt.Println("Es ist Sonntag.")
        default:
                fmt.Println("Es ist ein Arbeitstag.")
        }
}

for-Schleife

kontrolle_for.go
package main
 
import (
        "fmt"
)
 
func main() {
	// klassische for-Schleife
	for i := 1; i < 7; i++ {
		fmt.Println("Durchlauf (for)", i)
	}
 
	// while-Schleife
	j := 1
	for j < 7 {
		fmt.Println("Durchlauf (while)", j)
		j++
	}
 
	// Endlos-Schleife
	//k := 1
	//for {
	//	fmt.Println("Durchlauf (while)", k)
	//	k++
	//}
 
	// for-each-Schleife mit range
	slice := []string{"Otto", "Didi", "Heinz"}
	for index, character := range slice {
		fmt.Println(index, "Character", character)
	}
}

Übung

kontrolle_uebung.go
package main
 
import (
        "fmt"
)
 
func main() {
	// Übung: Alter vom Hund in Menschenjahren und Hundejahren
	for dogAge := 1; dogAge < 11; dogAge++ {
		HumanAge := dogAge * 7
		fmt.Printf("Dog: %d, Human %d\n", dogAge, HumanAge)
	}
}

Funktionen und Methoden

einfache Funktionen

einfache_Funktionen.go
package main
 
import (
        "fmt"
)
 
func humanAge1(dogAge int) int {
        return dogAge * 7 
}
 
func humanAge2(dogAge int) (humanAge int) {
        humanAge = dogAge * 7 
        return
}
 
func main() {
        // Übung: Alter vom Hund in Menschenjahren und Hundejahren
        hassoAge := 3
        fmt.Println("1. Menschenalter von Hasso", humanAge1(hassoAge))
        fmt.Println("2. Menschenalter von Hasso", humanAge2(hassoAge))
}

Funktionen mit mehreren Parametern und Rückgaben

Funktionen_mit_mehreren_Parametern.go
package main
 
import (
        "fmt"
)
 
func humanAge(dogAge int) int {
        return dogAge * 7
}
 
func humanAges(dog1, dog2 int) (int, int) {
        return humanAge(dog1), humanAge(dog2)
}
 
func main() {
        human1, human2 := humanAges(3, 5)
        fmt.Println("Human Ages:", human1, ",", human2)
}

Methoden an Strukturen definieren

Struct_mit_Methode.go
package main
 
import (
        "fmt"
)
 
// Struct
type Struktur01 struct {
	Name string    // mit großem Anfangsbuchstaben ist es ein öffentliches Feld
	alter int      // mit kleinem Anfangsbuchstaben ist es ein privates Feld
}
 
// Methode
func (c Struktur01) methode01() {
	fmt.Println("Ausgabe der Methode:", c.Name)
}
 
func main() {
	// normales Struct
	c := Struktur01{Name: "Alfred Nobel", alter: 63}
 
	// Aufruf Methode an Struct
	c.methode01()
 
	fmt.Println(c)
}

Mit Fehlern in Funktionen umgehen

Fehler_in_Funktionen.go
package main
 
import (
        "fmt"
)
 
// Struktur
type Congressman struct {
	Name           string
	AccountBalance float64
}
 
// Fehler als Rückgabewert
// Der Kontostand eines bestechlichen Abgeordneten wird von dieser Methode erhöht
// ist ein Abgeordneter nicht bestechlich, wird ein Fehler ausgegeben
func (c Congressman) bestechung(amount float64) error {
	// ist der Name des Abgeordneten nicht Peter, so ist er nicht bestechlich
	if c.Name != "Peter" {
		return fmt.Errorf("%v ist nicht koruppt", c.Name)
	}
 
	c.AccountBalance += amount
	fmt.Println(c.Name, "hat", c.AccountBalance)
 
	return nil
}
 
func main() {
	//c := Congressman{Name: "Jacjie", AccountBalance: 8000.0}
	c := Congressman{Name: "Peter", AccountBalance: 8000.0}
 
	// Fehler behandeln
	err := c.bestechung(5000.0)
	if err != nil {
		fmt.Println("Ein Abgeordneter konnte nicht bestochen werden:", err)
	}
 
	fmt.Println(c)
}

generische Funktionen

generische_Funktionen.go
package main
 
import (
        "log"
)
 
// generische Funktion
func humanAge[T int | float64](dogAge T) T {
	return dogAge * 7
}
 
func main() {
	// Funktion mit Typ Integer aufrufen
	var i int = humanAge(3)
	log.Println(i)
 
	// Funktion mit Typ Fließkomma aufrufen
	var j float64 = humanAge[float64](4.9)
	log.Println(j)
}

anonyme Funktionen

anonyme_Funktionen.go
package main
 
import (
	"fmt"
	"net/http"
)
 
func main() {
	// anonyme Funktion definieren und ausführen
	func () {
		fmt.Println("Hallo Welt")
	}()
 
	// anonyme HTTP-Handler-Funktion
	http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hallo Welt"))
	})
	http.ListenAndServe(":8080")
}

verzögerte Ausführung

verzögerte_Ausführung.go
package main
 
import (
        "fmt"
)
 
// mit defer kann eine Ausführung verzögert werden
func halloDefer() {
        defer fmt.Print("Welt\n")
 
        // defer wird auch bei einem Fehler ausgeführt
        // hier greifen wir in einem Slice auf eine Stelle (Index) zu,
        // die nicht existiert -> Fehler
        //var s = []string{}
        //fmt.Println("Huch ", s[42])
 
        fmt.Print("Hallo ")
}
 
func main() {
        // verzögerte Ausführung mit defer
        halloDefer()
}

Typische Anwendungsfälle für defer sind "Dateien schließen", "Dateien löschen" oder "Speicher freigeben".

Schnittstellen mit Interfaces

Das Interface

hallo_interface.go
package main
 
import (
        "fmt"
)
 
type Congressman struct {
        Name string
}
 
func (c Congressman) greet() {
        fmt.Println("Hallo", c.Name)
}
 
type Enemy struct{}
 
func (e Enemy) greet() {
        fmt.Println("Go to hell!")
}
 
// Interface definieren
type Greeter interface {
        greet()
}
 
// Interface nutzen
func passBy(g1, g2 Greeter) {
        g1.greet()
        g2.greet()
}
 
func main() {
        // Interface
        c := Congressman{Name: "Frank"}
        e := Enemy{}
 
        passBy(c, e)
}

Interfaces werden in Go nicht explizit, sondern implizit integriert.

Das Interface Stringer aus der Std-Lib

Stringer.go
package main
 
import (
        "fmt"
)
 
type Struktur01 struct {
	Name string
}
 
func (c Struktur01) Sring() string {
	return "Hallo! " + c.Name
}
 
func main() {
	c := Struktur01{Name: "Alfred Nobel"}
	fmt.Println(c)
}
$ go doc fmt.Stringer
package fmt // import "fmt"
 
type Stringer interface {
	String() string
}
    Stringer is implemented by any value that has a String method, which defines
    the “native” format for that value. The String method is used to print
    values passed as an operand to any format that accepts a string or to an
    unformatted printer such as Print.

Das leere Interface

leeres_interface.go
package main
 
import (
        "fmt"
)
 
func main() {
        // Das leere Interface
        var i interface{} = "Hallo"
 
        // Type Assertion heißt in anderen Sprachen Cast -> Typ-Umwandlung
 
        // Type Assertion ohne Prüfung
        var s string = i.(string)
        fmt.Println(s)
 
        // Type Assertion mit Prüfung
        s2, ok := i.(string)
        fmt.Println(s2, "ist es ein String?", ok)
 
        // falsche Type Assertion ohne Prüfung erzeugt Panic
        var f float64 = i.(float64)
        fmt.Println(f)
}

Das io.Reader-Interface JSON verarbeiten

io-Reader-Interface.go
package main
 
import (
        "fmt"
        "strings"
        "encoding/json"
)
 
func main() {
        // normales Struct
        const jsonBody = `{ "Nachricht": "Hallo Leser!" }`
        var jsonMap map[string]string
 
        r := strings.NewReader(jsonBody)
 
        json.NewDecoder(r).Decode(&jsonMap)
 
        fmt.Println(jsonMap)
}

Nebenläufig programmieren

Mit Go-Routinen und Channels nebenläufig programmieren

Go-Routine.go
package main
 
import (
        "fmt"
)
 
func Hallo(gruss string) {
        fmt.Println("Hallo", gruss)
}
 
func main() {
        // Go-Routine
        go Hallo("Welt")
}
Go-Channel.go
package main
 
import (
        "fmt"
)
 
// Deklarieren und Initialisieren
//a := make(chan string)
//
// Nachricht über Channel senden
//a <- "Hallo"
//
// Nachricht von Channel empfangen,
// "Pfeil" gibt Richtung des Datenflusses an
//value = <-a
//
//func Hallo(gruss string) {
//      fmt.Println("Hallo", gruss)
//}
//
//func main() {
//      // Go-Channel
//      go Hallo("Welt")
//}
 
func main() {
        // 1. Channel erzeugen
        money := make(chan int)
 
        go func () {
                // 3. Receive auf Channel money
                amount := <-money
                fmt.Println("empfangen:", amount, "€")
        }()
 
        // 2. an Channel senden
        money <- 200
}
2-Sekunden_Go-Channel.go
package main
 
import (
        "fmt"
        "time"
)
 
func  cashflow(money chan int) {
        amount := <-money
        fmt.Println("empfangen:", amount, "€")
}
 
func main() { 
        money := make(chan int)
        go cashflow(money)
 
        money <- 1000
 
        time.Sleep(2 * time.Second)
}
mehrere_Go-Channels.go
package main
 
import (
        "fmt"
        "time"
)
 
func  cashflow(money chan int) {
        // mit Select kann man gleichzeitig auf mehrere Channels lauschen
        select {
        case amount := <-money:
                fmt.Println("empfangen:", amount, "€")
        case <-time.After(1 * time.Second):
                fmt.Println("...kein Geld bekommen!!!")
        }
}
 
func main() {
        money := make(chan int)
        go cashflow(money)
 
//      money <- 1000
 
        time.Sleep(2 * time.Second)
}
parallele_Worker.go
package main
 
import (
        "fmt"
        "time"
        "sync"
)
 
func worker(id int) {
        fmt.Printf("Worker %d startet\n", id)
 
        // durch schlafen wird aufwändige Verarbeitung simuliert
        time.Sleep(time.Second)
 
        fmt.Printf("Worker %d ist fertig\n", id)
}
 
func main() {
        // Parallele Worker mit der WaitGroup
        var wg sync.WaitGroup
 
        // hier werden 5 Worker in einer Schleife nacheinander gestartet
        for i := 1; i <= 5; i++ {
                wg.Add(1)
                // weil sich alle Worker die Variable "i" teilen, brauchen wir hier noch eine eigene Kopie von "i"
                i := i
 
                go func() {
                        defer wg.Done()
                        worker(i)
                }()
        }
 
        // hier warten wir, bis alle Worker fertig sind
        wg.Wait()
}
parallele_Worker_-_Debatte.go
package main
 
import (
        "fmt"
        "time"
        "math/rand"
)
 
func speaker(name string, debate chan int) {
        for {
                microphone := <-debate // auf Mic warten (Nachricht empfangen)
 
                fmt.Printf("Turn %v: %v says '%v'\n", microphone, name, randomAnswer())
                time.Sleep(400 * time.Millisecond)
 
                microphone++
                debate <- microphone // Mic zurückgeben (Nachricht senden)
        }
}
 
func randomAnswer() string {
        answers := []string{"Ich habe Recht", "Nimm dieses Argument.", "Aber ich habe diese Erfahrung gemacht.", "Du ***"}
        return answers[rand.Intn(len(answers)-1)]
}
 
func main() {
        debate := make(chan int)
 
        go speaker("Jackie", debate)
        go speaker("Frank", debate)
 
        microphone := 1
 
        debate <- microphone
 
        time.Sleep(2 * time.Second)
 
        <-debate
}

Praktische Aufgabe: Webserver für Go Proverbs

Basisprogramm: Webserver Proverbs

> go mod init proserve
> go get github.com/jboursiquot/go-proverbs
go: downloading github.com/jboursiquot/go-proverbs v0.0.2
go: added github.com/jboursiquot/go-proverbs v0.0.2
Webserver_Proverbs.go
package main
 
import (
        "net/http"
)
 
func main() {
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
                w.Write([]byte("Hallo Proserve!\n"))
        })
        http.ListenAndServe(":8000", nil)
}
> go build Webserver_Proverbs.go
> ./Webserver_Proverbs &
[1] 274944
 
> jobs
[1]+  Läuft                  ./Webserver_Proverbs &
 
> curl localhost:8000
Hallo Proserve!
 
> killall Webserver_Proverbs
> jobs
[1]+  Beendet                 ./Webserver_Proverbs

Dieses Programm werden wir im folgenden erweitern…

Ersten Plain-Text-API-Endpoint umsetzen

Webserver_Proverbs.go
package main
 
import (
        "fmt"
        "net/http"
        "github.com/jboursiquot/go-proverbs"
)
 
func main() {
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
                w.Write([]byte("Hallo Proserve!"))
        })
 
        // Plain Text Endpunkt
        http.HandleFunc("/text", func(w http.ResponseWriter, r *http.Request) {
                fmt.Fprintf(w, proverbs.Random().Saying)
        })
 
        http.ListenAndServe(":8000", nil)
}
> curl localhost:8000/ ; echo
Hallo Proserve!
 
> curl localhost:8000/text ; echo
Make the zero value useful.

JSON-Endpoint

Webserver_Proverbs.go
package main
 
import (
        "fmt"
        "net/http"
        "github.com/jboursiquot/go-proverbs"
        "encoding/json"
)
 
type Proverb struct {
        Saying string `json:"saying"`
        Link string `json:"link"`
}
 
func HandleProverbJson(w http.ResponseWriter, r *http.Request) {
        randomProverb := proverbs.Random()
 
        p := Proverb {
                Saying: randomProverb.Saying,
                Link: randomProverb.Link,
        }
 
        err := json.NewEncoder(w).Encode(p)
        if err != nil {
                http.Error(w, "uups, da ist etwas schief gegangen!", http.StatusInternalServerError)
        }
}
 
func main() {
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
                w.Write([]byte("Hallo Proserve!"))
        })
 
        // Plain Text Endpunkt
        http.HandleFunc("/text", func(w http.ResponseWriter, r *http.Request) {
                fmt.Fprintf(w, proverbs.Random().Saying)
        })
 
        // JSON Endpunkt
        http.HandleFunc("/api", HandleProverbJson)
 
        http.ListenAndServe(":8000", nil)
}
> curl localhost:8000/api ; echo
{"saying":"interface{} says nothing.","link":"https://www.youtube.com/watch?v=PAAkCSZUG1c\u0026t=7m36s"}

Unit-Test: JSON-Endpoint

Webserver_Proverbs_test.go
package main
 
import (
        "net/http"
        "net/http/httptest"
        "testing"
)
 
type TestHandleProverbJson(t *testing.T) {
        // 1. HTTP Recorder erstellen
        recorder := httptest.NewRecorder()
 
        // 2. HTTP Request
        req, _ := http.NewRequest)"GET", "/api", nil)
 
        // 3. HTTP-Händler aufrufen
        HandleProverbJson(recorder, req)
 
        // 4. Ergebnis prüfen
        if recorder.Code != http.StatusOK {
                t.Errorf("fehlerhafter Status %v, erwarteter Status %v", recorder.Code, http.StatusOK)
        }
}

Fehler behandeln

Webserver_Proverbs.go
package main
 
import (
        "fmt"
        "net/http"
        "github.com/jboursiquot/go-proverbs"
        "encoding/json"
        "log"
)
 
type Proverb struct {
        Saying string `json:"saying"`
        Link string `json:"link"`
}
 
func HandleProverbJson(w http.ResponseWriter, r *http.Request) {
        randomProverb := proverbs.Random()
 
        p := Proverb {
                Saying: randomProverb.Saying,
                Link: randomProverb.Link,
        }
 
        err := json.NewEncoder(w).Encode(p)
        if err != nil {
                http.Error(w, "uups, da ist etwas schief gegangen!", http.StatusInternalServerError)
        }
}
 
func main() {
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
                w.Write([]byte("Hallo Proserve!"))
        })
 
        // Plain Text Endpunkt
        http.HandleFunc("/text", func(w http.ResponseWriter, r *http.Request) {
                _, err := fmt.Fprintf(w, proverbs.Random().Saying)
                if err != nil {
                        http.Error(w, "uups, da ist etwas schief gegangen!", http.StatusInternalServerError)
                }
        })
 
        // JSON Endpunkt
        http.HandleFunc("/api", HandleProverbJson)
 
        err := http.ListenAndServe(":8000", nil)
        if err != nil {
                log.Fatal(err)
        }
}
> ./Webserver_Proverbs &
[1] 293523
 
> ./Webserver_Proverbs
2026/01/27 16:32:12 listen tcp :8000: bind: address already in use
 
> killall Webserver_Proverbs

HTML-Seite für Proverbs

Webserver_Proverbs.go
package main
 
import (
        "fmt"
        "net/http"
        "github.com/jboursiquot/go-proverbs"
        "encoding/json"
        "log"
        "html/template"
)
 
type Proverb struct {
        Saying string `json:"saying"`
        Link string `json:"link"`
}
 
func HandleProverbJson(w http.ResponseWriter, r *http.Request) {
        randomProverb := proverbs.Random()
 
        p := Proverb {
                Saying: randomProverb.Saying,
                Link: randomProverb.Link,
        }
 
        err := json.NewEncoder(w).Encode(p)
        if err != nil {
                http.Error(w, "uups, da ist etwas schief gegangen!", http.StatusInternalServerError)
        }
}
 
func HandleProverbPage(w http.ResponseWriter, r *http.Request) {
        t, _ := template.New("page").Parse(`<html>
        <head></head>
        <body>
                <h1>Your Proverb: <a href="{{ .Link }}">{{ .Saying }}</a></h1>
        </body>
</html>`)
        err := t.Execute(w, proverbs.Random())
        if err != nil {
                http.Error(w, "uups, da ist etwas schief gegangen!", http.StatusInternalServerError)
        }
}
 
func main() {
        http.HandleFunc("/", HandleProverbPage)
 
        // Plain Text Endpunkt
        http.HandleFunc("/text", func(w http.ResponseWriter, r *http.Request) {
                _, err := fmt.Fprintf(w, proverbs.Random().Saying)
                if err != nil {
                        http.Error(w, "uups, da ist etwas schief gegangen!", http.StatusInternalServerError)
                }
        })
 
        // JSON Endpunkt
        http.HandleFunc("/api", HandleProverbJson)
 
        err := http.ListenAndServe(":8000", nil)
        if err != nil {
                log.Fatal(err)
        }
}
> ./Webserver_Proverbs &
[1] 296083
 
> curl localhost:8000/ ; echo
<html>
	<head></head>
	<body>
		<h1>Your Proverb: <a href="https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;t=5m17s">The bigger the interface, the weaker the abstraction.</a></h1>
	</body>
</html>
 
> killall Webserver_Proverbs

Das Makefile

Makefile
BINARY = "Webserver_Proverbs"
 
clean:
        rm -f ${BINARY}
 
build: clean
        go build -o ${BINARY} .

Das Zen von Go

  1. einfach
    • Go erreicht viel mit wenig. Ein Programm sollte eine Sache tun, und die gut.
  2. bescheiden
    • Unser Kode soll klar, idiomatisch und verständlich sein und seinen Zweck gut erfüllen. Clever ist da hinderlich.
  3. Handeln durch Nichthandeln
    • Probleme eliminieren und Umwege vermeiden. Bewusstes Nichthandeln als Alternative zur Problemlösung und Umsetzung nutzen.

Ideen für erste Projekte

  • Go eignet sich besonders für…
    • Microservices
    • Serverless Funktions
    • Kommandozeilen-Tools
    • DevOps und Cloud-Automatisierung

...weiter machen...

/home/http/wiki/data/pages/go_lernen.txt · Zuletzt geändert: von manfred