Benutzer-Werkzeuge

Webseiten-Werkzeuge


go_lernen

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
go_lernen [2026-01-26 17:06:06] – [Das Interface] manfredgo_lernen [2026-01-28 10:47:47] (aktuell) manfred
Zeile 16: Zeile 16:
  
 <code bash Hallo Welt> <code bash Hallo Welt>
-> vim hello_gopher.go+> vim hallo_gopher.go
 package main package main
 import ( import (
Zeile 25: Zeile 25:
 } }
  
-> go build hello_gopher.go +> go build hallo_gopher.go 
-> ./hello_gopher+> ./hallo_gopher
 Hallo Gopher! Hallo Gopher!
 </code> </code>
Zeile 138: Zeile 138:
 Arrays haben eine feste Länge. Arrays haben eine feste Länge.
  
-Slices haben eine variable Länge, es entspricht einer "Liste" in C++ oder Java.+Slices haben eine variable Länge, es entspricht einer "Liste" in ''%%C++%%'' oder ''Java''.
  
 <code go Array> <code go Array>
Zeile 728: Zeile 728:
  
 //Interfaces werden in Go nicht explizit, sondern implizit integriert.// //Interfaces werden in Go nicht explizit, sondern implizit integriert.//
 +
 +
 +=== Das Interface Stringer aus der Std-Lib ===
 +
 +<code go 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)
 +}
 +</code>
 +
 +<code text>
 +$ 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.
 +</code>
 +
 +
 +=== Das leere Interface ===
 +
 +<code go 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)
 +}
 +</code>
 +
 +
 +=== Das io.Reader-Interface JSON verarbeiten ===
 +
 +<code go 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)
 +}
 +</code>
 +
 +
 +==== Nebenläufig programmieren ====
 +
 +
 +=== Mit Go-Routinen und Channels nebenläufig programmieren ===
 +
 +<code go Go-Routine.go>
 +package main
 +
 +import (
 +        "fmt"
 +)
 +
 +func Hallo(gruss string) {
 +        fmt.Println("Hallo", gruss)
 +}
 +
 +func main() {
 +        // Go-Routine
 +        go Hallo("Welt")
 +}
 +</code>
 +
 +<code go 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
 +}
 +</code>
 +
 +<code go 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)
 +}
 +</code>
 +
 +<code go 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)
 +}
 +</code>
 +
 +<code go 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()
 +}
 +</code>
 +
 +<code go 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
 +}
 +</code>
 +
 +
 +==== Praktische Aufgabe: Webserver für Go Proverbs ====
 +
 +
 +=== Basisprogramm: Webserver Proverbs ===
 +
 +<code bash>
 +> 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
 +</code>
 +
 +<code go 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)
 +}
 +</code>
 +
 +<code bash>
 +> 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
 +</code>
 +
 +//Dieses Programm werden wir im folgenden erweitern...//
 +
 +
 +=== Ersten Plain-Text-API-Endpoint umsetzen ===
 +
 +<code go 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)
 +}
 +</code>
 +
 +<code bash>
 +> curl localhost:8000/ ; echo
 +Hallo Proserve!
 +
 +> curl localhost:8000/text ; echo
 +Make the zero value useful.
 +</code>
 +
 +
 +=== JSON-Endpoint ===
 +
 +<code go 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)
 +}
 +</code>
 +
 +<code bash>
 +> curl localhost:8000/api ; echo
 +{"saying":"interface{} says nothing.","link":"https://www.youtube.com/watch?v=PAAkCSZUG1c\u0026t=7m36s"}
 +</code>
 +
 +
 +=== Unit-Test: JSON-Endpoint ===
 +
 +<code go 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)
 +        }
 +}
 +</code>
 +
 +
 +=== Fehler behandeln ===
 +
 +<code go 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)
 +        }
 +}
 +</code>
 +
 +<code bash>
 +> ./Webserver_Proverbs &
 +[1] 293523
 +
 +> ./Webserver_Proverbs
 +2026/01/27 16:32:12 listen tcp :8000: bind: address already in use
 +
 +> killall Webserver_Proverbs
 +</code>
 +
 +
 +=== HTML-Seite für Proverbs ===
 +
 +<code go 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)
 +        }
 +}
 +</code>
 +
 +<code html>
 +> ./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
 +</code>
 +
 +
 +=== Das Makefile ===
 +
 +<file make Makefile>
 +BINARY = "Webserver_Proverbs"
 +
 +clean:
 +        rm -f ${BINARY}
 +
 +build: clean
 +        go build -o ${BINARY} .
 +</file>
 +
 +
 +==== Das Zen von Go ====
 +
 +  - **einfach**
 +    * Go erreicht viel mit wenig. Ein Programm sollte eine Sache tun, und die gut.
 +  - **bescheiden**
 +    * Unser Kode soll klar, idiomatisch und verständlich sein und seinen Zweck gut erfüllen. Clever ist da hinderlich.
 +  - **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... =====
 +
 +[[https://www.linkedin.com/learning/code-challenges-fur-go/kompakte-programmierratsel-in-go-mit-unterschiedlichen-schwierigkeitsgraden-losen|Code-Challenges für Go]]
  
  
/home/http/wiki/data/attic/go_lernen.1769447166.txt · Zuletzt geändert: von manfred