go_lernen
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende Überarbeitung | ||
| go_lernen [2026-01-26 18:03:13] – [Das io.Reader-Interface JSON] manfred | go_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! | ||
| </ | </ | ||
| 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 " | + | Slices haben eine variable Länge, es entspricht einer " |
| <code go Array> | <code go Array> | ||
| Zeile 800: | Zeile 800: | ||
| <code go io-Reader-Interface.go> | <code go io-Reader-Interface.go> | ||
| + | package main | ||
| + | |||
| + | import ( | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ) | ||
| + | |||
| + | func main() { | ||
| + | // normales Struct | ||
| + | const jsonBody = `{ " | ||
| + | var jsonMap map[string]string | ||
| + | |||
| + | r := strings.NewReader(jsonBody) | ||
| + | |||
| + | json.NewDecoder(r).Decode(& | ||
| + | |||
| + | fmt.Println(jsonMap) | ||
| + | } | ||
| </ | </ | ||
| + | |||
| + | |||
| + | ==== Nebenläufig programmieren ==== | ||
| + | |||
| + | |||
| + | === Mit Go-Routinen und Channels nebenläufig programmieren === | ||
| + | |||
| + | <code go Go-Routine.go> | ||
| + | package main | ||
| + | |||
| + | import ( | ||
| + | " | ||
| + | ) | ||
| + | |||
| + | func Hallo(gruss string) { | ||
| + | fmt.Println(" | ||
| + | } | ||
| + | |||
| + | func main() { | ||
| + | // Go-Routine | ||
| + | go Hallo(" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <code go Go-Channel.go> | ||
| + | package main | ||
| + | |||
| + | import ( | ||
| + | " | ||
| + | ) | ||
| + | |||
| + | // Deklarieren und Initialisieren | ||
| + | //a := make(chan string) | ||
| + | // | ||
| + | // Nachricht über Channel senden | ||
| + | //a <- " | ||
| + | // | ||
| + | // Nachricht von Channel empfangen, | ||
| + | // " | ||
| + | //value = <-a | ||
| + | // | ||
| + | //func Hallo(gruss string) { | ||
| + | // fmt.Println(" | ||
| + | //} | ||
| + | // | ||
| + | //func main() { | ||
| + | // // Go-Channel | ||
| + | // go Hallo(" | ||
| + | //} | ||
| + | |||
| + | func main() { | ||
| + | // 1. Channel erzeugen | ||
| + | money := make(chan int) | ||
| + | |||
| + | go func () { | ||
| + | // 3. Receive auf Channel money | ||
| + | amount := <-money | ||
| + | fmt.Println(" | ||
| + | }() | ||
| + | |||
| + | // 2. an Channel senden | ||
| + | money <- 200 | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <code go 2-Sekunden_Go-Channel.go> | ||
| + | package main | ||
| + | |||
| + | import ( | ||
| + | " | ||
| + | " | ||
| + | ) | ||
| + | |||
| + | func cashflow(money chan int) { | ||
| + | amount := <-money | ||
| + | fmt.Println(" | ||
| + | } | ||
| + | |||
| + | func main() { | ||
| + | money := make(chan int) | ||
| + | go cashflow(money) | ||
| + | |||
| + | money <- 1000 | ||
| + | |||
| + | time.Sleep(2 * time.Second) | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <code go mehrere_Go-Channels.go> | ||
| + | package main | ||
| + | |||
| + | import ( | ||
| + | " | ||
| + | " | ||
| + | ) | ||
| + | |||
| + | func cashflow(money chan int) { | ||
| + | // mit Select kann man gleichzeitig auf mehrere Channels lauschen | ||
| + | select { | ||
| + | case amount := <-money: | ||
| + | fmt.Println(" | ||
| + | case < | ||
| + | fmt.Println(" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | func main() { | ||
| + | money := make(chan int) | ||
| + | go cashflow(money) | ||
| + | |||
| + | // money <- 1000 | ||
| + | |||
| + | time.Sleep(2 * time.Second) | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <code go parallele_Worker.go> | ||
| + | package main | ||
| + | |||
| + | import ( | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ) | ||
| + | |||
| + | func worker(id int) { | ||
| + | fmt.Printf(" | ||
| + | |||
| + | // durch schlafen wird aufwändige Verarbeitung simuliert | ||
| + | time.Sleep(time.Second) | ||
| + | |||
| + | fmt.Printf(" | ||
| + | } | ||
| + | |||
| + | 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 := i | ||
| + | |||
| + | go func() { | ||
| + | defer wg.Done() | ||
| + | worker(i) | ||
| + | }() | ||
| + | } | ||
| + | |||
| + | // hier warten wir, bis alle Worker fertig sind | ||
| + | wg.Wait() | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <code go parallele_Worker_-_Debatte.go> | ||
| + | package main | ||
| + | |||
| + | import ( | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ) | ||
| + | |||
| + | func speaker(name string, debate chan int) { | ||
| + | for { | ||
| + | microphone := <-debate // auf Mic warten (Nachricht empfangen) | ||
| + | |||
| + | fmt.Printf(" | ||
| + | time.Sleep(400 * time.Millisecond) | ||
| + | |||
| + | microphone++ | ||
| + | debate <- microphone // Mic zurückgeben (Nachricht senden) | ||
| + | } | ||
| + | } | ||
| + | |||
| + | func randomAnswer() string { | ||
| + | answers := []string{" | ||
| + | return answers[rand.Intn(len(answers)-1)] | ||
| + | } | ||
| + | |||
| + | func main() { | ||
| + | debate := make(chan int) | ||
| + | |||
| + | go speaker(" | ||
| + | go speaker(" | ||
| + | |||
| + | microphone := 1 | ||
| + | |||
| + | debate <- microphone | ||
| + | |||
| + | time.Sleep(2 * time.Second) | ||
| + | |||
| + | <-debate | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== Praktische Aufgabe: Webserver für Go Proverbs ==== | ||
| + | |||
| + | |||
| + | === Basisprogramm: | ||
| + | |||
| + | <code bash> | ||
| + | > go mod init proserve | ||
| + | > go get github.com/ | ||
| + | go: downloading github.com/ | ||
| + | go: added github.com/ | ||
| + | </ | ||
| + | |||
| + | <code go Webserver_Proverbs.go> | ||
| + | package main | ||
| + | |||
| + | import ( | ||
| + | " | ||
| + | ) | ||
| + | |||
| + | func main() { | ||
| + | http.HandleFunc("/", | ||
| + | w.Write([]byte(" | ||
| + | }) | ||
| + | http.ListenAndServe(": | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <code bash> | ||
| + | > go build Webserver_Proverbs.go | ||
| + | > ./ | ||
| + | [1] 274944 | ||
| + | |||
| + | > jobs | ||
| + | [1]+ Läuft | ||
| + | |||
| + | > curl localhost: | ||
| + | Hallo Proserve! | ||
| + | |||
| + | > killall Webserver_Proverbs | ||
| + | > jobs | ||
| + | [1]+ Beendet | ||
| + | </ | ||
| + | |||
| + | //Dieses Programm werden wir im folgenden erweitern...// | ||
| + | |||
| + | |||
| + | === Ersten Plain-Text-API-Endpoint umsetzen === | ||
| + | |||
| + | <code go Webserver_Proverbs.go> | ||
| + | package main | ||
| + | |||
| + | import ( | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ) | ||
| + | |||
| + | func main() { | ||
| + | http.HandleFunc("/", | ||
| + | w.Write([]byte(" | ||
| + | }) | ||
| + | |||
| + | // Plain Text Endpunkt | ||
| + | http.HandleFunc("/ | ||
| + | fmt.Fprintf(w, | ||
| + | }) | ||
| + | |||
| + | http.ListenAndServe(": | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <code bash> | ||
| + | > curl localhost: | ||
| + | Hallo Proserve! | ||
| + | |||
| + | > curl localhost: | ||
| + | Make the zero value useful. | ||
| + | </ | ||
| + | |||
| + | |||
| + | === JSON-Endpoint === | ||
| + | |||
| + | <code go Webserver_Proverbs.go> | ||
| + | package main | ||
| + | |||
| + | import ( | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ) | ||
| + | |||
| + | type Proverb struct { | ||
| + | Saying string `json:" | ||
| + | Link string `json:" | ||
| + | } | ||
| + | |||
| + | func HandleProverbJson(w http.ResponseWriter, | ||
| + | randomProverb := proverbs.Random() | ||
| + | |||
| + | p := Proverb { | ||
| + | Saying: randomProverb.Saying, | ||
| + | Link: randomProverb.Link, | ||
| + | } | ||
| + | |||
| + | err := json.NewEncoder(w).Encode(p) | ||
| + | if err != nil { | ||
| + | http.Error(w, | ||
| + | } | ||
| + | } | ||
| + | |||
| + | func main() { | ||
| + | http.HandleFunc("/", | ||
| + | w.Write([]byte(" | ||
| + | }) | ||
| + | |||
| + | // Plain Text Endpunkt | ||
| + | http.HandleFunc("/ | ||
| + | fmt.Fprintf(w, | ||
| + | }) | ||
| + | |||
| + | // JSON Endpunkt | ||
| + | http.HandleFunc("/ | ||
| + | |||
| + | http.ListenAndServe(": | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <code bash> | ||
| + | > curl localhost: | ||
| + | {" | ||
| + | </ | ||
| + | |||
| + | |||
| + | === Unit-Test: JSON-Endpoint === | ||
| + | |||
| + | <code go Webserver_Proverbs_test.go> | ||
| + | package main | ||
| + | |||
| + | import ( | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ) | ||
| + | |||
| + | type TestHandleProverbJson(t *testing.T) { | ||
| + | // 1. HTTP Recorder erstellen | ||
| + | recorder := httptest.NewRecorder() | ||
| + | |||
| + | // 2. HTTP Request | ||
| + | req, _ := http.NewRequest)" | ||
| + | |||
| + | // 3. HTTP-Händler aufrufen | ||
| + | HandleProverbJson(recorder, | ||
| + | |||
| + | // 4. Ergebnis prüfen | ||
| + | if recorder.Code != http.StatusOK { | ||
| + | t.Errorf(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | |||
| + | === Fehler behandeln === | ||
| + | |||
| + | <code go Webserver_Proverbs.go> | ||
| + | package main | ||
| + | |||
| + | import ( | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ) | ||
| + | |||
| + | type Proverb struct { | ||
| + | Saying string `json:" | ||
| + | Link string `json:" | ||
| + | } | ||
| + | |||
| + | func HandleProverbJson(w http.ResponseWriter, | ||
| + | randomProverb := proverbs.Random() | ||
| + | |||
| + | p := Proverb { | ||
| + | Saying: randomProverb.Saying, | ||
| + | Link: randomProverb.Link, | ||
| + | } | ||
| + | |||
| + | err := json.NewEncoder(w).Encode(p) | ||
| + | if err != nil { | ||
| + | http.Error(w, | ||
| + | } | ||
| + | } | ||
| + | |||
| + | func main() { | ||
| + | http.HandleFunc("/", | ||
| + | w.Write([]byte(" | ||
| + | }) | ||
| + | |||
| + | // Plain Text Endpunkt | ||
| + | http.HandleFunc("/ | ||
| + | _, err := fmt.Fprintf(w, | ||
| + | if err != nil { | ||
| + | http.Error(w, | ||
| + | } | ||
| + | }) | ||
| + | |||
| + | // JSON Endpunkt | ||
| + | http.HandleFunc("/ | ||
| + | |||
| + | err := http.ListenAndServe(": | ||
| + | if err != nil { | ||
| + | log.Fatal(err) | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <code bash> | ||
| + | > ./ | ||
| + | [1] 293523 | ||
| + | |||
| + | > ./ | ||
| + | 2026/01/27 16:32:12 listen tcp :8000: bind: address already in use | ||
| + | |||
| + | > killall Webserver_Proverbs | ||
| + | </ | ||
| + | |||
| + | |||
| + | === HTML-Seite für Proverbs === | ||
| + | |||
| + | <code go Webserver_Proverbs.go> | ||
| + | package main | ||
| + | |||
| + | import ( | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ) | ||
| + | |||
| + | type Proverb struct { | ||
| + | Saying string `json:" | ||
| + | Link string `json:" | ||
| + | } | ||
| + | |||
| + | func HandleProverbJson(w http.ResponseWriter, | ||
| + | randomProverb := proverbs.Random() | ||
| + | |||
| + | p := Proverb { | ||
| + | Saying: randomProverb.Saying, | ||
| + | Link: randomProverb.Link, | ||
| + | } | ||
| + | |||
| + | err := json.NewEncoder(w).Encode(p) | ||
| + | if err != nil { | ||
| + | http.Error(w, | ||
| + | } | ||
| + | } | ||
| + | |||
| + | func HandleProverbPage(w http.ResponseWriter, | ||
| + | t, _ := template.New(" | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | </ | ||
| + | err := t.Execute(w, | ||
| + | if err != nil { | ||
| + | http.Error(w, | ||
| + | } | ||
| + | } | ||
| + | |||
| + | func main() { | ||
| + | http.HandleFunc("/", | ||
| + | |||
| + | // Plain Text Endpunkt | ||
| + | http.HandleFunc("/ | ||
| + | _, err := fmt.Fprintf(w, | ||
| + | if err != nil { | ||
| + | http.Error(w, | ||
| + | } | ||
| + | }) | ||
| + | |||
| + | // JSON Endpunkt | ||
| + | http.HandleFunc("/ | ||
| + | |||
| + | err := http.ListenAndServe(": | ||
| + | if err != nil { | ||
| + | log.Fatal(err) | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <code html> | ||
| + | > ./ | ||
| + | [1] 296083 | ||
| + | |||
| + | > curl localhost: | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | > killall Webserver_Proverbs | ||
| + | </ | ||
| + | |||
| + | |||
| + | === Das Makefile === | ||
| + | |||
| + | <file make Makefile> | ||
| + | BINARY = " | ||
| + | |||
| + | clean: | ||
| + | rm -f ${BINARY} | ||
| + | |||
| + | build: clean | ||
| + | go build -o ${BINARY} . | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== 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:// | ||
/home/http/wiki/data/attic/go_lernen.1769450593.txt · Zuletzt geändert: von manfred
