Menu
Coddy logo textTech

Embedding di più struct

Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 37 di 107.

Go ti consente di incorporare più struct in una singola struct, combinando comportamenti provenienti da fonti diverse. È simile all’ereditarietà multipla presente in altri linguaggi, ma utilizza l’approccio alla composizione di 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
}

La struct Service ora ha accesso ai metodi di entrambi i tipi incorporati:

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

Quando si incorporano più strutture, può verificarsi un conflitto di denominazione se due tipi incorporati hanno metodi con lo stesso nome. Go non risolve automaticamente questa ambiguità:

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() - error de compilación: selector ambiguo
    fmt.Println(c.A.Greet())  // Hello from A
    fmt.Println(c.B.Greet())  // Hello from B
}

Quando sorgono conflitti, devi specificare esplicitamente il metodo del tipo incorporato che vuoi chiamare, usando il nome del tipo come qualificatore.

challenge icon

Sfida

Facile

Costruiamo un sistema di dispositivi per la casa intelligente che combina più funzionalità tramite l’incorporamento di struct. Creerai un dispositivo in grado sia di controllare l’illuminazione sia di riprodurre musica, incorporando tipi di controller separati.

Organizzerai il codice in tre file:

  • controllers.go: crea due struct di controller indipendenti che forniscono funzionalità diverse:
    • Un LightController con un campo Brightness (int) e un metodo SetLight(level int) string che restituisce Light set to [level]%
    • Un AudioController con un campo Volume (int) e un metodo SetVolume(level int) string che restituisce Volume set to [level]%
    Entrambi i controller dovrebbero avere anche un metodo Status() string. Questo crea un conflitto di nomi che dovrai gestire. LightController.Status() dovrebbe restituire Brightness: [Brightness]% e AudioController.Status() dovrebbe restituire Volume: [Volume]%.
  • device.go: crea una struct SmartDevice con un campo Name che incorpora sia LightController sia AudioController. Aggiungi un metodo chiamato FullStatus() string che restituisce il nome del dispositivo insieme agli stati di entrambi i controller, risolvendo l’ambiguità chiamando esplicitamente il metodo Status() di ciascun tipo incorporato.
  • main.go: leggi la configurazione del dispositivo dall’input, crea uno SmartDevice, usa i metodi promossi per impostare i livelli di illuminazione e volume, quindi mostra lo stato completo.

Verranno forniti i seguenti input:

  • Riga 1: nome del dispositivo
  • Riga 2: livello di luminosità iniziale (intero)
  • Riga 3: livello di volume iniziale (intero)
  • Riga 4: nuovo livello di luminosità da impostare (intero)
  • Riga 5: nuovo livello di volume da impostare (intero)

Il tuo metodo FullStatus() dovrebbe restituire:

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

Stampa i risultati delle chiamate a SetLight e SetVolume (promossi dai tipi incorporati), quindi stampa lo stato completo.

Ad esempio, dati Living Room Hub, 50, 30, 75 e 60, il tuo output dovrebbe essere:

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

Nota che SetLight e SetVolume sono accessibili direttamente su SmartDevice tramite la promozione dei metodi, mentre Status() richiede una qualificazione esplicita perché entrambi i tipi incorporati hanno quel metodo.

Provalo tu

package main

import (
	"fmt"
)

func main() {
	// Leggi l'input
	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: Crea uno SmartDevice con il nome e i valori iniziali forniti

	// TODO: Usa il metodo promosso SetLight e stampa il risultato

	// TODO: Usa il metodo promosso SetVolume e stampa il risultato

	// TODO: Stampa lo stato completo usando il metodo FullStatus()
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Go online