Menu
Coddy logo textTech

Grundlagen der Reflection

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

Reflektion ermöglicht es einem Programm, seine eigene Struktur zur Laufzeit zu untersuchen und zu bearbeiten. Gos Paket reflect stellt diese Funktionalität bereit und ermöglicht es dir, Typen zu untersuchen, Struct-Felder zu lesen und Methoden dynamisch aufzurufen.

Die beiden grundlegenden Typen bei der Reflektion sind reflect.Type und reflect.Value. Du erhältst sie mit reflect.TypeOf() und reflect.ValueOf():

import "reflect"

type Person struct {
    Name string
    Age  int
}

p := Person{Name: "Alice", Age: 30}

t := reflect.TypeOf(p)
v := reflect.ValueOf(p)

fmt.Println(t.Name())       // Person
fmt.Println(t.Kind())       // struct
fmt.Println(v.NumField())   // 2

Du kannst über Struct-Felder iterieren, um ihre Namen, Typen und Werte zu untersuchen:

for i := 0; i < t.NumField(); i++ {
    field := t.Field(i)
    value := v.Field(i)
    fmt.Printf("%s: %v\n", field.Name, value)
}
// Ausgabe:
// Name: Alice
// Age: 30

Reflection ist leistungsstark, bringt aber Kompromisse mit sich: Sie umgeht die Typprüfung zur Kompilierzeit, läuft langsamer als der direkte Zugriff und macht den Code schwerer verständlich. Verwende sie sparsam für Aufgaben wie JSON-Marshaling, ORM-Mapping oder das Erstellen generischer Dienstprogramme, bei denen der Typ zur Kompilierzeit nicht bekannt ist.

challenge icon

Aufgabe

Einfach

Erstelle einen Struct-Inspektor, der Reflection verwendet, um jeden Struct zu untersuchen und seine Struktur zu melden! Dies ist ein praktischer Anwendungsfall für Reflection: das Erstellen von Hilfsprogrammen, die mit Typen arbeiten, die zur Kompilierzeit unbekannt sind.

Du organisierst deinen Code auf zwei Dateien verteilt:

  • inspector.go: Erstelle dein auf Reflection basierendes Inspektionsprogramm.

    Erstelle eine Funktion InspectStruct(v any) string, die das Paket reflect verwendet, um jeden an sie übergebenen Struct zu untersuchen. Deine Funktion soll einen formatierten Bericht zurückgeben, der Folgendes enthält:

    • Den Typnamen des Structs
    • Die Art des Structs (sollte "struct" sein)
    • Die Anzahl der Felder
    • Für jedes Feld: den Feldnamen, seinen Typ und seinen aktuellen Wert

    Das Ausgabeformat sollte wie folgt aussehen:

    Type: [TypeName]
    Kind: struct
    Fields: [count]
    - [FieldName] ([FieldType]): [Value]
    - [FieldName] ([FieldType]): [Value]
    ...

    Verwende reflect.TypeOf(), um Typinformationen abzurufen, und reflect.ValueOf(), um auf Feldwerte zuzugreifen. Iteriere mithilfe von NumField() über die Felder, mit Field(i) auf dem Typ für Metadaten und mit Field(i) auf dem Wert für die tatsächlichen Werte.

  • main.go: Definiere Beispiel-Structs und verwende deinen Inspektor.

    Lies einen Struct-Typ (product oder employee) und seine Feldwerte ein, erstelle anschließend den entsprechenden Struct und untersuche ihn.

    Für product: Erstelle einen Product-Struct mit den Feldern Name (string), Price (float64) und InStock (bool). Lies den Namen, den Preis und den Lagerstatus ein.

    Für employee: Erstelle einen Employee-Struct mit den Feldern ID (int), Name (string) und Department (string). Lies die ID, den Namen und die Abteilung ein.

    Übergib den erstellten Struct an InspectStruct und gib das Ergebnis aus.

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Struct-Typ (product oder employee)
  • Folgende Zeilen: Feldwerte für diesen Struct-Typ

Beispiel für folgende Eingabe:

product
Laptop
999.99
true

Deine Ausgabe sollte wie folgt aussehen:

Type: Product
Kind: struct
Fields: 3
- Name (string): Laptop
- Price (float64): 999.99
- InStock (bool): true

Und bei folgender Eingabe:

employee
42
Alice Johnson
Engineering

Deine Ausgabe sollte wie folgt aussehen:

Type: Employee
Kind: struct
Fields: 3
- ID (int): 42
- Name (string): Alice Johnson
- Department (string): Engineering

Und bei folgender Eingabe:

product
Headphones
79.50
false

Deine Ausgabe sollte wie folgt aussehen:

Type: Product
Kind: struct
Fields: 3
- Name (string): Headphones
- Price (float64): 79.5
- InStock (bool): false

Beachte, wie dein Inspektor mit unterschiedlichen Struct-Typen arbeitet, ohne ihre Struktur im Voraus zu kennen. Das ist die Stärke von Reflection! Dieselbe Funktion InspectStruct verarbeitet sowohl Product- als auch Employee-Structs dynamisch.

Probier es selbst

package main

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

// Product-Struct mit den Feldern Name, Price und InStock
type Product struct {
	Name    string
	Price   float64
	InStock bool
}

// Employee-Struct mit den Feldern ID, Name und Department
type Employee struct {
	ID         int
	Name       string
	Department string
}

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Struct-Typ einlesen
	structType, _ := reader.ReadString('\n')
	structType = strings.TrimSpace(structType)

	if structType == "product" {
		// Product-Felder einlesen
		name, _ := reader.ReadString('\n')
		name = strings.TrimSpace(name)

		priceStr, _ := reader.ReadString('\n')
		priceStr = strings.TrimSpace(priceStr)
		price, _ := strconv.ParseFloat(priceStr, 64)

		inStockStr, _ := reader.ReadString('\n')
		inStockStr = strings.TrimSpace(inStockStr)
		inStock, _ := strconv.ParseBool(inStockStr)

		// TODO: Erstelle ein Product-Struct mit den gelesenen Werten
		// TODO: Rufe InspectStruct mit dem Produkt auf und gib das Ergebnis aus

	} else if structType == "employee" {
		// Employee-Felder einlesen
		idStr, _ := reader.ReadString('\n')
		idStr = strings.TrimSpace(idStr)
		id, _ := strconv.Atoi(idStr)

		name, _ := reader.ReadString('\n')
		name = strings.TrimSpace(name)

		department, _ := reader.ReadString('\n')
		department = strings.TrimSpace(department)

		// TODO: Erstelle ein Employee-Struct mit den gelesenen Werten
		// TODO: Rufe InspectStruct mit dem Employee auf und gib das Ergebnis aus

	}
}
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