Menu
Coddy logo textTech

Einbetten mehrerer Structs

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

Go ermöglicht es Ihnen, mehrere structs in ein einzelnes struct einzubetten und so Verhaltensweisen aus verschiedenen Quellen zu kombinieren. Dies ähnelt der Mehrfachvererbung in anderen Sprachen, jedoch mit dem Kompositionsansatz von Go.

type Logger struct{}

func (l Logger) Log(msg string) string {
    return "LOG: " + msg
}

type Notifier struct{}

func (n Notifier) Notify(msg string) string {
    return "NOTIFY: " + msg
}

type Service struct {
    Name string
    Logger
    Notifier
}

Die Service-Struct hat nun Zugriff auf Methoden beider eingebetteten Typen:

func main() {
    s := Service{Name: "OrderService"}
    fmt.Println(s.Log("started"))      // LOG: started
    fmt.Println(s.Notify("new order")) // NOTIFY: new order
}

Beim Einbetten mehrerer Structs kann ein Namenskonflikt auftreten, wenn zwei eingebettete Typen Methoden mit demselben Namen haben. Go löst diese Mehrdeutigkeit nicht automatisch auf:

type A struct{}
func (A) Greet() string { return "Hello from A" }

type B struct{}
func (B) Greet() string { return "Hello from B" }

type Combined struct {
    A
    B
}

func main() {
    c := Combined{}
    // c.Greet() - Kompilierfehler: mehrdeutiger Selektor
    fmt.Println(c.A.Greet())  // Hello from A
    fmt.Println(c.B.Greet())  // Hello from B
}

Wenn Konflikte auftreten, müssen Sie explizit angeben, welche Methode des eingebetteten Typs Sie aufrufen möchten, indem Sie den Typnamen als Qualifizierer verwenden.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Smart-Home-Gerätesystem bauen, das mehrere Funktionen durch Struct-Embedding kombiniert. Sie werden ein Gerät erstellen, das sowohl die Beleuchtung steuern als auch Musik abspielen kann, indem Sie separate Controller-Typen einbetten.

Sie werden Ihren Code über drei Dateien organisieren:

  • controllers.go: Erstellen Sie zwei unabhängige Controller-Structs, die unterschiedliche Funktionen bieten:
    • Ein LightController mit einem Brightness-Feld (int) und einer SetLight(level int) string-Methode, die "Light set to [level]%" zurückgibt.
    • Ein AudioController mit einem Volume-Feld (int) und einer SetVolume(level int) string-Methode, die "Volume set to [level]%" zurückgibt.
    Beide Controller sollten außerdem eine Status() string-Methode haben – dies erzeugt einen Namenskonflikt, den Sie behandeln müssen. LightController.Status() sollte "Brightness: [Brightness]%" zurückgeben und AudioController.Status() sollte "Volume: [Volume]%" zurückgeben.
  • device.go: Erstellen Sie ein SmartDevice-Struct mit einem Name-Feld, das sowohl LightController als auch AudioController einbettet. Fügen Sie eine Methode namens FullStatus() string hinzu, die den Gerätenamen zusammen mit beiden Controller-Stati zurückgibt und die Mehrdeutigkeit auflöst, indem sie explizit die Status()-Methode jedes eingebetteten Typs aufruft.
  • main.go: Lesen Sie die Gerätekonfiguration aus der Eingabe, erstellen Sie ein SmartDevice, verwenden Sie die promoteten Methoden, um Licht- und Lautstärkepegel einzustellen, und zeigen Sie dann den vollständigen Status an.

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Gerätename
  • Zeile 2: Initialer Helligkeitswert (Integer)
  • Zeile 3: Initialer Lautstärkewert (Integer)
  • Zeile 4: Neuer einzustellender Helligkeitswert (Integer)
  • Zeile 5: Neuer einzustellender Lautstärkewert (Integer)

Ihre FullStatus()-Methode sollte Folgendes zurückgeben:

[Name] - [LightController.Status()], [AudioController.Status()]

Geben Sie die Ergebnisse des Aufrufs von SetLight und SetVolume aus (die von den eingebetteten Typen promotet werden), und geben Sie dann den vollständigen Status aus.

Zum Beispiel, gegeben "Living Room Hub", 50, 30, 75 und 60, sollte Ihre Ausgabe wie folgt aussehen:

Light set to 75%
Volume set to 60%
Living Room Hub - Brightness: 75%, Volume: 60%

Beachten Sie, wie SetLight und SetVolume durch Method Promotion direkt auf SmartDevice zugänglich sind, aber Status() eine explizite Qualifizierung erfordert, da beide eingebetteten Typen diese Methode besitzen.

Spickzettel

Go ermöglicht das Einbetten mehrerer Structs in ein einzelnes Struct, wobei Verhaltensweisen aus verschiedenen Quellen durch Komposition kombiniert werden:

type Logger struct{}

func (l Logger) Log(msg string) string {
    return "LOG: " + msg
}

type Notifier struct{}

func (n Notifier) Notify(msg string) string {
    return "NOTIFY: " + msg
}

type Service struct {
    Name string
    Logger
    Notifier
}

Das Service-Struct hat Zugriff auf Methoden beider eingebetteten Typen:

s := Service{Name: "OrderService"}
fmt.Println(s.Log("started"))      // LOG: started
fmt.Println(s.Notify("new order")) // NOTIFY: new order

Namenskonflikte treten auf, wenn eingebettete Typen Methoden mit demselben Namen haben. Sie müssen explizit angeben, welche Methode des eingebetteten Typs aufgerufen werden soll:

type A struct{}
func (A) Greet() string { return "Hello from A" }

type B struct{}
func (B) Greet() string { return "Hello from B" }

type Combined struct {
    A
    B
}

// c.Greet() - Kompilierfehler: mehrdeutiger Selektor
c := Combined{}
fmt.Println(c.A.Greet())  // Hello from A
fmt.Println(c.B.Greet())  // Hello from B

Probier es selbst

package main

import (
	"fmt"
)

func main() {
	// Eingabe lesen
	var name string
	fmt.Scanln(&name)

	var initialBrightness int
	fmt.Scanln(&initialBrightness)

	var initialVolume int
	fmt.Scanln(&initialVolume)

	var newBrightness int
	fmt.Scanln(&newBrightness)

	var newVolume int
	fmt.Scanln(&newVolume)

	// TODO: Erstellen Sie ein SmartDevice mit dem angegebenen Namen und den Anfangswerten

	// TODO: Verwenden Sie die heraufgestufte SetLight-Methode und geben Sie das Ergebnis aus

	// TODO: Verwenden Sie die heraufgestufte SetVolume-Methode und geben Sie das Ergebnis aus

	// TODO: Geben Sie den vollständigen Status mit der Methode FullStatus() 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