Go in 10 Minuten lernen
Go (auch bekannt als Golang) ist eine statisch typisierte, kompilierte Programmiersprache, die bei Google entwickelt wurde. Sie ist bekannt für ihre Einfachheit, Effizienz und hervorragende Unterstützung für Nebenläufigkeit. Dieses Tutorial hilft dir, schnell Go-Programmierung zu lernen.
1. Dein erstes Go-Programm schreiben
Beginnen wir mit einem einfachen Programm. Erstelle eine Datei namens hello.go
und gib folgenden Code ein:
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
Speichere die Datei und führe folgenden Befehl im Terminal aus:
go run hello.go
Die Ausgabe wird sein:
Hello, World!
Dieses einfache Programm demonstriert die grundlegende Struktur von Go:
package main
deklariert den Paketnamenimport "fmt"
importiert das Format-Paket für Ein-/Ausgabe-Operationenfunc main()
ist der Einstiegspunkt des Programmsfmt.Println()
gibt Text auf der Konsole aus
2. Grundlegende Syntax
Go hat eine saubere und einfache Syntax. Im Gegensatz zu Python verwendet Go geschweifte Klammern {}
zur Definition von Codeblöcken und erfordert Semikolons am Ende von Anweisungen (obwohl sie normalerweise automatisch eingefügt werden).
// Dies ist ein einzeiliger Kommentar
fmt.Println("Hello, World!")
/*
Dies ist ein mehrzeiliger Kommentar,
der sich über mehrere Zeilen erstreckt
*/
Grundlegende Syntax-Regeln in Go:
- Codeblöcke: Werden durch geschweifte Klammern
{}
definiert - Kommentare: Einzeilige Kommentare beginnen mit
//
, mehrzeilige mit/* */
- Anweisungen: Enden mit Semikolons (automatisch eingefügt)
- Paket-Deklaration: Jede Datei beginnt mit einer Paket-Deklaration
3. Variablen und Datentypen
Go ist statisch typisiert, was bedeutet, dass du Variablentypen deklarieren musst. Allerdings unterstützt Go Typinferenz mit dem :=
Operator.
Methoden zur Variablendeklaration:
// Explizite Typdeklaration
var name string = "John"
var age int = 25
// Typinferenz
name := "John"
age := 25
// Mehrfache Variablendeklaration
var x, y int = 10, 20
x, y := 10, 20
Hauptgrunddatentypen von Go:
- Ganzzahltypen:
int
,int8
,int16
,int32
,int64
,uint
,uint8
,uint16
,uint32
,uint64
,uintptr
- Gleitkommatypen:
float32
,float64
- String:
string
- Boolean:
bool
- Komplexe Typen:
complex64
,complex128
3.1 Numerische Typen
Go bietet verschiedene numerische Typen für verschiedene Anwendungsfälle:
// Ganzzahltypen
var age int = 25
var smallNumber int8 = 127
var largeNumber int64 = 9223372036854775807
// Gleitkommatypen
var temperature float32 = 36.5
var pi float64 = 3.14159265359
// Komplexe Zahlen
var complexNum complex64 = 3 + 4i
3.2 String-Typ
Strings in Go sind Byte-Sequenzen und sind unveränderlich:
// String-Deklaration
var greeting string = "Hello, Go!"
name := "Alice"
// String-Operationen
fmt.Println(len(greeting)) // String-Länge
fmt.Println(greeting[0]) // Auf erstes Zeichen zugreifen (Byte)
fmt.Println(greeting[0:5]) // String-Slicing
fmt.Println(strings.ToUpper(name)) // In Großbuchstaben umwandeln
3.3 Boolean-Typ
Der Boolean-Typ hat zwei Werte: true
und false
:
var isActive bool = true
var isComplete bool = false
// Boolean-Operationen
result1 := true && false // false
result2 := true || false // true
result3 := !true // false
4. Konstanten
Konstanten werden mit dem const
Schlüsselwort deklariert und können nicht geändert werden:
const Pi = 3.14159
const MaxUsers = 1000
// Mehrere Konstanten
const (
StatusOK = 200
StatusNotFound = 404
StatusError = 500
)
// Typisierte Konstanten
const Version string = "1.0.0"
5. Datenstrukturen
Go bietet mehrere eingebaute Datenstrukturen zum Speichern und Manipulieren von Daten.
5.1 Arrays
Arrays sind feste Sequenzen von Elementen desselben Typs:
// Array-Deklaration
var numbers [5]int = [5]int{1, 2, 3, 4, 5}
names := [3]string{"Alice", "Bob", "Charlie"}
// Auf Elemente zugreifen
fmt.Println(numbers[0]) // 1
numbers[0] = 10 // Element ändern
// Array-Länge
fmt.Println(len(numbers)) // 5
5.2 Slices
Slices sind dynamische Arrays, die wachsen und schrumpfen können:
// Slice-Deklaration
numbers := []int{1, 2, 3, 4, 5}
var emptySlice []int
// Slices aus Arrays erstellen
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4] // [2, 3, 4]
// Slice-Operationen
numbers = append(numbers, 6) // Element hinzufügen
numbers = append(numbers, 7, 8, 9) // Mehrere Elemente hinzufügen
// Slice-Kapazität und Länge
fmt.Println(len(numbers)) // Länge: 9
fmt.Println(cap(numbers)) // Kapazität: 10 (kann variieren)
5.3 Maps
Maps sind ungeordnete Sammlungen von Schlüssel-Wert-Paaren:
// Map-Deklaration
student := map[string]interface{}{
"name": "John",
"age": 20,
"major": "Computer Science",
}
// Alternative Deklaration
var scores map[string]int = make(map[string]int)
scores["math"] = 95
scores["science"] = 88
// Zugreifen und Ändern
fmt.Println(student["name"])
student["age"] = 21
student["gpa"] = 3.8
// Sicherer Zugriff
if phone, exists := student["phone"]; exists {
fmt.Println(phone)
} else {
fmt.Println("Telefon nicht angegeben")
}
// Über Map iterieren
for key, value := range student {
fmt.Printf("%s: %v\n", key, value)
}
5.4 Structs
Structs sind Sammlungen von Feldern, die verschiedene Typen haben können:
// Struct-Definition
type Person struct {
Name string
Age int
City string
}
// Struct-Instanzen erstellen
person1 := Person{"Alice", 25, "New York"}
person2 := Person{
Name: "Bob",
Age: 30,
City: "London",
}
// Auf Felder zugreifen
fmt.Println(person1.Name)
person1.Age = 26
6. Operationen und Operatoren
Go bietet einen umfangreichen Satz von Operatoren für verschiedene Berechnungen und Vergleiche.
- Arithmetische Operatoren:
+
,-
,*
,/
,%
(Modulo) - Vergleichsoperatoren:
==
,!=
,>
,<
,>=
,<=
- Logische Operatoren:
&&
,||
,!
- Bitweise Operatoren:
&
,|
,^
,<<
,>>
- Zuweisungsoperatoren:
=
,+=
,-=
,*=
,/=
6.1 Arithmetische Operatoren
a, b := 10, 3
fmt.Printf("Addition: %d\n", a + b) // 13
fmt.Printf("Subtraktion: %d\n", a - b) // 7
fmt.Printf("Multiplikation: %d\n", a * b) // 30
fmt.Printf("Division: %d\n", a / b) // 3
fmt.Printf("Modulo: %d\n", a % b) // 1
6.2 Vergleichsoperatoren
x, y := 5, 10
fmt.Printf("Gleich: %t\n", x == y) // false
fmt.Printf("Ungleich: %t\n", x != y) // true
fmt.Printf("Größer als: %t\n", x > y) // false
fmt.Printf("Kleiner als: %t\n", x < y) // true
6.3 Logische Operatoren
a, b := true, false
fmt.Printf("UND-Operation: %t\n", a && b) // false
fmt.Printf("ODER-Operation: %t\n", a || b) // true
fmt.Printf("NICHT-Operation: %t\n", !a) // false
7. Kontrollfluss
Go bietet mehrere Kontrollfluss-Anweisungen zur Steuerung der Programmausführung.
7.1 if-Anweisungen
age := 20
if age >= 18 {
fmt.Println("Erwachsener")
} else if age >= 13 {
fmt.Println("Jugendlicher")
} else {
fmt.Println("Kind")
}
// if mit kurzer Anweisung
if score := 85; score >= 90 {
fmt.Println("Note: A")
} else if score >= 80 {
fmt.Println("Note: B")
} else {
fmt.Println("Note: C")
}
7.2 for-Schleifen
Go hat nur eine Schleifenkonstruktion: for
// Grundlegende for-Schleife
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// While-artige Schleife
count := 0
for count < 5 {
fmt.Println(count)
count++
}
// Endlosschleife
for {
fmt.Println("Dies läuft für immer")
break // Verwende break zum Verlassen
}
// Range-Schleife (für Slices, Arrays, Maps)
fruits := []string{"Apfel", "Banane", "Kirsche"}
for index, fruit := range fruits {
fmt.Printf("%d: %s\n", index, fruit)
}
7.3 switch-Anweisungen
day := "Monday"
switch day {
case "Monday":
fmt.Println("Wochenanfang")
case "Friday":
fmt.Println("Wochenende naht")
case "Saturday", "Sunday":
fmt.Println("Wochenende!")
default:
fmt.Println("Normaler Tag")
}
// Switch ohne Ausdruck
score := 85
switch {
case score >= 90:
fmt.Println("Note: A")
case score >= 80:
fmt.Println("Note: B")
case score >= 70:
fmt.Println("Note: C")
default:
fmt.Println("Note: F")
}
8. Funktionen
Funktionen in Go sind First-Class-Citizens und unterstützen mehrere Rückgabewerte.
8.1 Grundlegende Funktionen
func greet(name string) string {
return "Hello, " + name + "!"
}
// Funktion aufrufen
message := greet("John")
fmt.Println(message)
8.2 Mehrere Rückgabewerte
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("Division durch Null nicht möglich")
}
return a / b, nil
}
// Mehrere Rückgabewerte verwenden
result, err := divide(10, 2)
if err != nil {
fmt.Println("Fehler:", err)
} else {
fmt.Println("Ergebnis:", result)
}
8.3 Benannte Rückgabewerte
func calculateRectangle(width, height float64) (area float64, perimeter float64) {
area = width * height
perimeter = 2 * (width + height)
return // "naked return"
}
area, perimeter := calculateRectangle(5, 3)
fmt.Printf("Fläche: %.2f, Umfang: %.2f\n", area, perimeter)
8.4 Variadische Funktionen
func sum(numbers ...int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
fmt.Println(sum(1, 2, 3, 4)) // 10
fmt.Println(sum(5, 10, 15)) // 30
9. Zeiger
Go hat Zeiger, aber mit einfacherer Syntax als C/C++:
func modifyValue(x *int) {
*x = *x * 2
}
func main() {
value := 10
fmt.Println("Vorher:", value) // 10
modifyValue(&value)
fmt.Println("Nachher:", value) // 20
}
10. Methoden
Methoden sind Funktionen mit einem Empfänger-Argument:
type Rectangle struct {
Width float64
Height float64
}
// Methode mit Wertempfänger
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// Methode mit Zeigerempfänger
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
rect := Rectangle{Width: 5, Height: 3}
fmt.Println("Fläche:", rect.Area()) // 15
rect.Scale(2)
fmt.Println("Skalierte Fläche:", rect.Area()) // 60
11. Interfaces
Interfaces definieren Methodensignaturen, die Typen implementieren können:
type Shape interface {
Area() float64
Perimeter() float64
}
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return 3.14159 * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * 3.14159 * c.Radius
}
func printShapeInfo(s Shape) {
fmt.Printf("Fläche: %.2f, Umfang: %.2f\n", s.Area(), s.Perimeter())
}
circle := Circle{Radius: 5}
printShapeInfo(circle)
12. Fehlerbehandlung
Go verwendet explizite Fehlerbehandlung statt Ausnahmen:
func readFile(filename string) (string, error) {
data, err := os.ReadFile(filename)
if err != nil {
return "", fmt.Errorf("Datei %s konnte nicht gelesen werden: %w", filename, err)
}
return string(data), nil
}
content, err := readFile("example.txt")
if err != nil {
fmt.Println("Fehler:", err)
return
}
fmt.Println("Inhalt:", content)
13. Nebenläufigkeit mit Goroutines
Goroutines sind leichtgewichtige Threads, die von der Go-Laufzeitumgebung verwaltet werden:
func worker(id int) {
for i := 0; i < 3; i++ {
fmt.Printf("Worker %d: %d\n", id, i)
time.Sleep(time.Millisecond * 100)
}
}
func main() {
// Mehrere Goroutines starten
for i := 1; i <= 3; i++ {
go worker(i)
}
// Auf Abschluss der Goroutines warten
time.Sleep(time.Second)
fmt.Println("Alle Worker abgeschlossen")
}
14. Kanäle
Kanäle werden für die Kommunikation zwischen Goroutines verwendet:
func producer(ch chan<- int) {
for i := 0; i < 5; i++ {
ch <- i // Wert an Kanal senden
time.Sleep(time.Millisecond * 100)
}
close(ch) // Kanal schließen, wenn fertig
}
func consumer(ch <-chan int) {
for value := range ch {
fmt.Println("Empfangen:", value)
}
}
func main() {
ch := make(chan int, 3) // Gepufferter Kanal
go producer(ch)
consumer(ch)
fmt.Println("Kanal-Kommunikation abgeschlossen")
}
15. Dateioperationen
Go bietet einfache Methoden zum Lesen und Schreiben von Dateien:
// Dateien lesen
data, err := os.ReadFile("example.txt")
if err != nil {
fmt.Println("Fehler beim Lesen der Datei:", err)
return
}
fmt.Println("Dateiinhalt:", string(data))
// Dateien schreiben
content := "Hello, Go!\n"
err = os.WriteFile("output.txt", []byte(content), 0644)
if err != nil {
fmt.Println("Fehler beim Schreiben der Datei:", err)
return
}
fmt.Println("Datei erfolgreich geschrieben")
16. Pakete und Module
Go-Module verwalten Abhängigkeiten und Paketversionen:
// Standardbibliothekspakete importieren
import (
"fmt"
"math"
"strings"
)
func main() {
fmt.Println(math.Sqrt(16)) // 4
fmt.Println(strings.ToUpper("go")) // GO
}
Um dein eigenes Paket zu erstellen, erstelle ein Verzeichnis mit deinem Paketnamen und exportiere Funktionen, indem du ihre Namen groß schreibst.
17. Testen
Go hat eingebaute Testunterstützung:
// In Datei math_test.go
package main
import "testing"
func TestAdd(t *testing.T) {
result := add(2, 3)
expected := 5
if result != expected {
t.Errorf("add(2, 3) = %d; erwartet %d", result, expected)
}
}
func add(a, b int) int {
return a + b
}
Führe Tests aus mit: go test
18. Best Practices
- Verwende
gofmt
zum Formatieren deines Codes - Folge den Go-Namenskonventionen (camelCase für Variablen, PascalCase für Exporte)
- Behandle Fehler explizit
- Verwende Interfaces für Abstraktion
- Bevorzuge Komposition gegenüber Vererbung
- Schreibe umfassende Tests
- Verwende die Standardbibliothek wann immer möglich
Dieses Tutorial deckt die wesentlichen Funktionen der Go-Programmierung ab. Mit Übung wirst du in der Lage sein, effiziente und nebenläufige Anwendungen mit den leistungsstarken Funktionen von Go zu erstellen.