215 lines
7.8 KiB
Markdown
215 lines
7.8 KiB
Markdown
# 2.4 Struct
|
|
|
|
## Struct
|
|
|
|
Wie in anderen Programmiersprachen können wir auch in Go neue Datentypen erstellen, die als eine "Struktur" verknüpfte Eigenschaften oder Felder zusammenfasst. So können wir Beipielsweise einen neuen Datentyp `person` erschaffen, dessen Eingenschaften der Name und das Alter einer Person sind. Wir nennen diesen Datentyp `struct`.
|
|
|
|
type person struct {
|
|
name string
|
|
alter int
|
|
}
|
|
|
|
Es sieht ziemlich einfach aus, ein `struct` zu definieren, nicht?
|
|
|
|
Es gibt insgesamt zwei Eigenschaften.
|
|
|
|
- `name` ist ein `string` und wird genutzt, um den Namen einer Person zu speichern.
|
|
- `alter` is vom Typ `int` und beinhaltet das Alter einer Person.
|
|
|
|
Schauen wir uns das einmal praktisch an.
|
|
|
|
type person struct {
|
|
name string
|
|
alter int
|
|
}
|
|
|
|
var P person // p ist vom Typ person
|
|
|
|
P.name = "Astaxie" // Weise "Astaxie" der Eigenschaft 'name' von p zu
|
|
P.alter = 25 // Weise 25 der Eigenschaft 'alter' von p zu
|
|
fmt.Printf("Der Name der Person lautet %s\n", P.name) // Rufe die Eigenschaft 'name' von p auf
|
|
|
|
Es gibt noch drei weitere Wege, ein Struct zu definieren.
|
|
|
|
- Weise Startwerte in der Reihenfolge der Eigenschaften zu.
|
|
|
|
P := person{"Tom", 25}
|
|
|
|
- Oder nutze das Schema `Eigenschaft:Wert`, um ein Struct zu erstellen, ohne dabei auf die Reihenfolge achten zu müssen.
|
|
|
|
P := person{alter:24, name:"Bob"}
|
|
|
|
- Definiere ein "anonymes" Struct und vergebe Startwerte
|
|
|
|
P := struct{name string; alter int}{"Amy",18}
|
|
|
|
Schauen wir uns das vollständige Beispiel an.
|
|
|
|
package main
|
|
import "fmt"
|
|
|
|
// Definiere einen neuen Datentyp
|
|
type person struct {
|
|
name string
|
|
alter int
|
|
}
|
|
|
|
// Vergleiche das Alter von zwei Personen. Dann gibt die ältere Person und den Altersunterschied zurück
|
|
// Structs werden als normaler Wert übergeben
|
|
func Älter(p1, p2 person) (person, int) {
|
|
if p1.alter>p2.alter {
|
|
return p1, p1.alter-p2.alter
|
|
}
|
|
return p2, p2.alter-p1.alter
|
|
}
|
|
|
|
func main() {
|
|
var tom person
|
|
|
|
// Initialisierung
|
|
tom.name, tom.alter = "Tom", 18
|
|
|
|
// Initialisiere zwei Werte nach dem Schema "Eigenschaft:Wert"
|
|
bob := person{alter:25, name:"Bob"}
|
|
|
|
// Initialisiere die Eigenschaft nach der Reihenfolge
|
|
paul := person{"Paul", 43}
|
|
|
|
tb_Älter, tb_diff := Älter(tom, bob)
|
|
tp_Älter, tp_diff := Älter(tom, paul)
|
|
bp_Älter, bp_diff := Älter(bob, paul)
|
|
|
|
fmt.Printf("Von %s und %s ist %s um %d Jahre älter\n", tom.name, bob.name, tb_Älter.name, tb_diff)
|
|
|
|
fmt.Printf("Von %s und %s ist %s um %d Jahre älter\n", tom.name, paul.name, tp_Älter.name, tp_diff)
|
|
|
|
fmt.Printf("Von %s und %s ist %s um %d Jahre älter\n", bob.name, paul.name, bp_Älter.name, bp_diff)
|
|
}
|
|
|
|
### Eigenschaften in Structs einbetten
|
|
|
|
Soeben habe ich Dir gezeigt, wie Du ein Struct mit Eigenschaften und Datentypen definieren kannst. Aber Go unterstützt auch Eigenschaften, die keinen Namen besitzen und nur dessen Datentyp angegeben wird. Wir bezeichnen diese als eingebettete Eigenschaften.
|
|
|
|
Wenn die eingebette Eigenschaft ein weiteres Struct ist, dann all seine Eigenschaften in den Struct übertragen, in dem es eingebettet wurde.
|
|
|
|
Betrachten wir ein Beispiel.
|
|
|
|
package main
|
|
import "fmt"
|
|
|
|
type Mensch struct {
|
|
name string
|
|
alter int
|
|
gewicht int
|
|
}
|
|
|
|
type Student struct {
|
|
Mensch // Eingebettete Eigenschaft, d.h. Student besitzt alle Eigenschaften von Mensch.
|
|
fachgebiet string
|
|
}
|
|
|
|
func main() {
|
|
// Initialisierng eines Studenten
|
|
mark := Student{Mensch{"Mark", 25, 120}, "Informatik"}
|
|
|
|
// Eigenschaften aufrufen
|
|
fmt.Println("Sein Name lautet ", mark.name)
|
|
fmt.Println("Sein Alter ist ", mark.alter)
|
|
fmt.Println("Er wiegt ", mark.gewicht)
|
|
fmt.Println("Sein Fachgebiet ist ", mark.fachgebiet)
|
|
// Eigenschaften verändern
|
|
mark.fachgebiet = "Künstliche Intelligenz"
|
|
fmt.Println("Mark hat sein Fachgebiet gewechselt")
|
|
fmt.Println("Sein Fachgebiet lautet ", mark.fachgebiet)
|
|
// Alter ändern
|
|
fmt.Println("Mark wurde alt")
|
|
mark.alter = 46
|
|
fmt.Println("Sein Alter beträgt ", mark.alter, " Jahre")
|
|
// Gewicht ändern
|
|
fmt.Println("Mark ist kein Athlet mehr")
|
|
mark.gewicht += 60
|
|
fmt.Println("Er wiegt nun", mark.gewicht)
|
|
}
|
|
|
|

|
|
|
|
Abbildung 2.7 Einbettung von Mensch in Student
|
|
|
|
Wie Du siehst, können wir die Eigenschaften `alter` und `name` vom Typ Student genauso aufrufen, wie jene vom Typ Mensch. Genau so funktioniert das Einbetten. Ziemlich einfach, nicht wahr? Aber es gibt noch Kleinigkeit, die ich Dir zeigen möchte. Du kannst auch den Typ Mensch verwenden, um auf Eigenschaften von Student zurückzugreifen.
|
|
|
|
mark.Mensch = Mensch{"Marcus", 55, 220}
|
|
mark.Mensch.alter -= 1
|
|
|
|
In Go können alle Datenttypen eingebettet werden.
|
|
|
|
package main
|
|
import "fmt"
|
|
|
|
type Fähigkeiten []string
|
|
|
|
type Mensch struct {
|
|
name string
|
|
alter int
|
|
gewicht int
|
|
}
|
|
|
|
type Student struct {
|
|
Mensch // Struct als eingebettete Eigenschaft
|
|
Fähigkeiten // Slice vom Typ string als eingebettete Eigenschaft
|
|
int // Standard Datentyp als eingebettete Eigenschaft
|
|
fachgebiet string
|
|
}
|
|
|
|
func main() {
|
|
// Initialisiere Studentin Jane
|
|
jane := Student{Mensch:Mensch{"Jane", 35, 100}, fachgebiet:"Biologie"}
|
|
// Eigenschaften aufrufen
|
|
fmt.Println("Ihr Name lautet ", jane.name)
|
|
fmt.Println("Ihr Alter ist ", jane.alter)
|
|
fmt.Println("Sie wiegt ", jane.gewicht)
|
|
fmt.Println("Ihr Fachgebiet ist ", jane.fachgebiet)
|
|
// Änderung des Wertes der Eigenschaft fähigkeit
|
|
jane.Fähigkeiten = []string{"Anatomie"}
|
|
fmt.Println("Sie besitzt folgende Fähigkeiten: ", jane.Fähigkeiten)
|
|
fmt.Println("Sie hat zwei neue Fähigkeiten erworben ")
|
|
jane.Fähigkeiten = append(jane.Fähigkeiten, "Physik", "Golang")
|
|
fmt.Println("Sie besitzt nun folgende Fähigkeiten ", jane.Fähigkeiten)
|
|
// Veränderung einer eingebetteten Eigenschaft
|
|
jane.int = 3
|
|
fmt.Println("Ihre bevorzugte Nummer lautet", jane.int)
|
|
}
|
|
|
|
Im oberen Beispiel ist erkenntlich, dass alle Datentypen eingebettet werden und Funktionen auf ihre Werte zugreifen können.
|
|
|
|
Aber es gibt noch ein kleines Problem. Was geschieht, wenn Mensch die Eigenschaft `telefon` besitzt und Student eine Eigenschaft mit dem gleichen Namen besitzt?
|
|
|
|
Go nutzt einen einfachen Weg zur Unterscheidung. Um die Eigenschaft `telefon` von Student zu erhalten, nutzt Du weiterhein `Student.telefon`. Die gleichnahmige Eigenschaft von Mensch kannst Du erhalten, indem Du `Student.Mensch.telefon` verwendest. Wie Du siehst, muss einfach der eingebette Datentyp vorangestellt werden. Diese Fähigkeiten wird "überladen" genannt (im Englischen `overloading`).
|
|
|
|
package main
|
|
import "fmt"
|
|
|
|
type Mensch struct {
|
|
name string
|
|
alter int
|
|
telefon string // Mensch hat die Eigenschaft telefon
|
|
}
|
|
|
|
type Mitarbeiter struct {
|
|
Mensch // Eingebetter Datentyp Mensch
|
|
spezialisierung string
|
|
telefon string // Eigenschaft telefon in Mitarbeiter
|
|
}
|
|
|
|
func main() {
|
|
Bob := Mitarbeiter{Mensch{"Bob", 34, "777-444-XXXX"}, "Designer", "333-222"}
|
|
fmt.Println("Bobs berufliche Telefonnummer lautet ", Bob.telefon)
|
|
// Greife auf Eigenschaft telefon in Mensch zu
|
|
fmt.Println("Bobs private Telefonnummer lauet ", Bob.Mensch.telefon)
|
|
}
|
|
|
|
## Links
|
|
|
|
- [Inhaltsverzeichnis](preface.md)
|
|
- Vorheriger Abschnitt: [Kontrollstrukturen und Funktionen](02.3.md)
|
|
- Nächster Abschnitt: [Objektorientiertes Programmieren](02.5.md)
|