Benutzer-Werkzeuge

Webseiten-Werkzeuge


go_lernen

Dies ist eine alte Version des Dokuments!


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 hello_gopher.go
package main
import (
        "fmt"
)
func main() {
        fmt.Println("Hallo Gopher!")
}
 
> go build hello_gopher.go
> ./hello_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

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