Menu
Coddy logo textTech

Generische Strukturen

Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy. Lektion 70 von 107.

Genau wie Funktionen können auch Strukturen Typparameter haben. Eine generische Struktur ermöglicht es dir, Datenstrukturen zu erstellen, die mit jedem Typ funktionieren und dabei die Typsicherheit gewährleisten. Das ist ideal zum Erstellen wiederverwendbarer Container wie Stapel, Warteschlangen oder Schlüssel-Wert-Paare.

Um eine generische Struktur zu definieren, platziere den Typparameter nach dem Namen der Struktur:

type Box[T any] struct {
    Value T
}

func main() {
    intBox := Box[int]{Value: 42}
    strBox := Box[string]{Value: "hello"}
    
    fmt.Println(intBox.Value)  // 42
    fmt.Println(strBox.Value)  // hello
}

Im Gegensatz zu generischen Funktionen musst du den Typ beim Erstellen einer Instanz einer generischen Struktur ausdrücklich angeben. Go kann den Typ nicht allein aus dem Kontext ableiten.

Generische Structs können mehrere Typparameter haben, was sie ideal für Strukturen wie Paare oder Maps macht:

type Pair[K, V any] struct {
    Key   K
    Value V
}

p := Pair[string, int]{Key: "age", Value: 25}
fmt.Printf("%s: %d\n", p.Key, p.Value)  // age: 25

Sie können auch Einschränkungen anwenden, um sicherzustellen, dass die gespeicherten Typen bestimmte Operationen unterstützen:

type NumberBox[T int | float64] struct {
    Value T
}

nb := NumberBox[float64]{Value: 3.14}

Generische Structs bilden die Grundlage für den Aufbau typsicherer, wiederverwendbarer Datenstrukturen in Go. In der nächsten Lektion werden Sie lernen, wie Sie Methoden für diese generischen Typen definieren.

challenge icon

Aufgabe

Einfach

Erstellen wir ein generisches Inventarsystem, das verschiedene Arten von Elementen verfolgen kann! Du erstellst wiederverwendbare Containerstrukturen, die mit jedem Typ funktionieren und dabei vollständige Typsicherheit gewährleisten.

Du organisierst deinen Code über zwei Dateien:

  • inventory.go: Definiere deine generischen Containerstrukturen.

    Erstelle eine generische Struktur Item[T any] mit zwei Feldern: Name (string) und Data (vom Typ T). Dies stellt ein beliebiges Element mit zugehörigen Daten eines flexiblen Typs dar.

    Erstelle eine generische Struktur Container[T any] mit einem einzigen Feld Items, das ein Slice aus Item[T] enthält. Dieser Container kann mehrere Elemente desselben Datentyps speichern.

    Erstelle eine eingeschränkte generische Struktur PricedItem[T int | float64] mit drei Feldern: Name (string), Quantity (int) und Price (vom Typ T). Die Einschränkung stellt sicher, dass Preise immer numerisch sind.

    Implementiere eine Funktion NewContainer[T any]() *Container[T], die einen Zeiger auf einen leeren Container erstellt und zurückgibt.

    Implementiere eine Methode Add für *Container[T], die einen Namen (string) und Daten (T) entgegennimmt, ein Item erstellt und es an den Items-Slice des Containers anhängt.

    Implementiere eine Methode Count für Container[T], die die Anzahl der Elemente im Container zurückgibt.

  • main.go: Veranschauliche deine generischen Strukturen mit verschiedenen Typen.

    Lies einen Elementtyp (string, int oder priced) ein und anschließend eine Anzahl gefolgt von den Elementdetails.

    Für den Typ string: Lies Paare aus Namen und String-Daten ein. Erstelle einen Container[string], füge alle Elemente hinzu und gib anschließend jedes Element als [Name]: [Data] aus, gefolgt von der Gesamtanzahl.

    Für den Typ int: Lies Paare aus Namen und Ganzzahldaten ein. Erstelle einen Container[int], füge alle Elemente hinzu und gib anschließend jedes Element als [Name]: [Data] aus, gefolgt von der Gesamtanzahl.

    Für den Typ priced: Lies Tripel aus Name, Menge und Preis (als float) ein. Erstelle direkt Instanzen von PricedItem[float64] und gib jedes als [Name] x[Quantity] @ [Price] aus, wobei der Preis mit einer Dezimalstelle angezeigt wird.

    Gib die Anzahlzeile wie folgt aus: Total items: [count]

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Elementtyp (string, int oder priced)
  • Zeile 2: Anzahl der Elemente (Ganzzahl)
  • Folgende Zeilen: Elementdetails abhängig vom Typ

Zum Beispiel bei folgender Eingabe:

string
3
Book
Fiction Novel
Pen
Blue Ink
Notebook
Lined Paper

Deine Ausgabe sollte wie folgt aussehen:

Book: Fiction Novel
Pen: Blue Ink
Notebook: Lined Paper
Total items: 3

Und bei folgender Eingabe:

int
2
Apples
50
Oranges
30

Deine Ausgabe sollte wie folgt aussehen:

Apples: 50
Oranges: 30
Total items: 2

Und bei folgender Eingabe:

priced
2
Widget
10
19.99
Gadget
5
49.50

Deine Ausgabe sollte wie folgt aussehen:

Widget x10 @ 19.9
Gadget x5 @ 49.5
Total items: 2

Beachte, wie dieselbe Container-Struktur nahtlos sowohl mit Strings als auch mit Ganzzahlen funktioniert, während PricedItem eine Einschränkung verwendet, um sicherzustellen, dass für Preise nur numerische Typen verwendet werden können. Du musst beim Erstellen von Instanzen dieser generischen Strukturen den Typparameter ausdrücklich angeben.

Probier es selbst

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Elementtyp lesen
	scanner.Scan()
	itemType := scanner.Text()
	
	// Anzahl lesen
	scanner.Scan()
	count, _ := strconv.Atoi(scanner.Text())
	
	switch itemType {
	case "string":
		// TODO: Erstelle einen Container[string] mit NewContainer
		// TODO: Lies 'count' Elemente (jedes hat den Namen in einer Zeile, die Daten in der nächsten Zeile)
		// TODO: Füge jedes Element zum Container hinzu
		// TODO: Gib jedes Element als "[Name]: [Data]" aus
		// TODO: Gib "Total items: [count]" mit der Count-Methode aus
		
	case "int":
		// TODO: Erstelle einen Container[int] mit NewContainer
		// TODO: Lies 'count' Elemente (jedes hat den Namen in einer Zeile, Integer-Daten in der nächsten Zeile)
		// TODO: Füge jedes Element zum Container hinzu
		// TODO: Gib jedes Element als "[Name]: [Data]" aus
		// TODO: Gib "Total items: [count]" mit der Count-Methode aus
		
	case "priced":
		// TODO: Erstelle einen Slice, um PricedItem[float64]-Instanzen zu halten
		// TODO: Lies 'count' Elemente (jedes hat Name, Menge und Preis in separaten Zeilen)
		// TODO: Erstelle ein PricedItem[float64] für jedes und füge es zum Slice hinzu
		// TODO: Gib jedes Element als "[Name] x[Quantity] @ [Price]" aus, wobei der Preis eine Dezimalstelle anzeigt
		// TODO: Gib "Total items: [count]" aus
	}
	
	_ = scanner // Verwende scanner, um die Eingabe zu lesen
	_ = count   // Verwende count für die Schleife
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Go-Compiler