In Go ist ein struct eine Folge benannter Elemente, die Felder genannt werden. Jedes Feld hat einen Namen und einen Typ. Der Name eines Feldes muss innerhalb des Structs eindeutig sein. Structs lassen sich mit Klassen aus dem Paradigma der objektorientierten Programmierung vergleichen.
Ein neues Struct erstellst du mit den Schlüsselwörtern type und struct, und du legst den Namen und den Typ der Felder explizit fest.
Zum Beispiel definieren wir hier das Struct Shape, das den Namen einer Form und ihre Größe speichert:
type Shape struct {
name string
size int
}
Feldnamen in Structs folgen der Go-Konvention: Felder, deren Name mit einem Kleinbuchstaben beginnt, sind nur für Code im selben Paket sichtbar, während solche, deren Name mit einem Großbuchstaben beginnt, in anderen Paketen sichtbar sind.
Sobald du das struct definiert hast, musst du eine neue Instanz erstellen und dabei die Felder über ihren Feldnamen in beliebiger Reihenfolge festlegen:
s := Shape {
name: "Square",
size: 25,
}
Um Felder einer Instanz zu lesen oder zu ändern, verwendest du die .-Notation:
// Update the name and the size
s.name = "Circle"
s.size = 35
fmt.Printf("name: %s size: %d\n", s.name, s.size)
// Output: name: Circle size: 35
Felder, denen kein Anfangswert zugewiesen wurde, erhalten ihren Zero Value. Zum Beispiel:
s := Shape{name: "Circle"}
fmt.Printf("name: %s size: %d\n", s.name, s.size)
// Output: name: Circle size: 0
Du kannst eine Instanz eines struct erstellen, ohne die Feldnamen zu verwenden, solange du die Felder in der Reihenfolge festlegst:
s := Shape {
"Oval",
20,
}
Allerdings gilt diese Syntax als spröder Code, denn sie kann kaputtgehen, wenn ein Feld hinzugefügt wird, besonders wenn das neue Feld einen anderen Typ hat.
Im folgenden Beispiel fügen wir Shape ein zusätzliches Feld hinzu:
type Shape struct {
name string
description string // new field 'description' added
size int
}
s := Shape{
"Circle",
20,
}
// Since the second field of the struct is now a string and not an int,
// the compiler will throw an error when compiling the program:
// Output: cannot use 20 (type untyped int) as type string in field value
// Output: too few values in Shape{...}
Manchmal ist es praktisch, Funktionen zu haben, die uns beim Erstellen von Struct-Instanzen helfen.
Nach Konvention heißen diese Funktionen meist New oder ihr Name beginnt mit New. Da es aber ganz normale Funktionen sind, kannst du ihnen einen beliebigen Namen geben.
Sie erinnern dich vielleicht an Konstruktoren in anderen Sprachen, aber in Go sind es einfach normale Funktionen.
Im folgenden Beispiel wird eine dieser New-Funktionen verwendet, um eine neue Instanz von Shape zu erstellen und automatisch einen Standardwert für die size der Form zu setzen:
func NewShape(name string) Shape {
return Shape{
name: name,
size: 100, //default-value for size is 100
}
}
NewShape("Triangle")
// => Shape { name: "Triangle", size: 100 }
Der Einsatz von New-Funktionen kann folgende Vorteile haben:
New-Funktionen oft im selben Paket deklariert werden wie die Structs, die sie initialisieren, können sie sogar private Felder des Structs initialisierenIn dieser Übung organisierst du Rennen zwischen verschiedenen Arten von ferngesteuerten Autos. Jedes Auto hat seine eigene Geschwindigkeit und seine eigene Batterieentladung.
Autos starten mit vollen (100 %) Batterien. Jedes Mal, wenn du das Auto mit der Fernbedienung fährst, legt es die Geschwindigkeit des Autos in Metern zurück und verringert den verbleibenden Batterieprozentsatz um seine Batterieentladung.
Wenn die Batterie eines Autos unter seinem Batterieentladungsprozentsatz liegt, kannst du das Auto nicht mehr fahren.
Jede Rennstrecke hat ihre eigene Entfernung. Autos werden getestet, indem geprüft wird, ob sie die Strecke beenden können, ohne dass die Batterie leer wird.
Definiere ein Car-Struct mit den folgenden Feldern vom Typ int:
Definiere eine Funktion NewCar, mit der du ein ferngesteuertes Auto erstellen kannst. Sie nimmt die Geschwindigkeit des Autos in Metern und den Batterieentladungsprozentsatz als ihre beiden Parameter entgegen (beide vom Typ int) und gibt eine Car-Instanz zurück:
speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
// => Car{speed: 5, batteryDrain: 2, battery:100, distance: 0}
Definiere einen weiteren Struct-Typ namens Track mit dem Feld distance vom Typ Ganzzahl.
Definiere eine Funktion NewTrack, mit der du eine Rennstrecke erstellen kannst. Sie nimmt die Entfernung der Strecke in Metern als einzigen Parameter entgegen (vom Typ int):
distance := 800
track := NewTrack(distance)
// => Track{distance: 800}
Implementiere die Funktion Drive, die die Anzahl der gefahrenen Meter anhand der Geschwindigkeit des Autos aktualisiert und die Batterie entsprechend der Batterieentladung reduziert.
Wenn die Batterie nicht ausreicht, um noch einmal zu fahren, bewegt sich das Auto nicht:
speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
car = Drive(car)
// => Car{speed: 5, batteryDrain: 2, battery: 98, distance: 5}
Um ein Rennen zu beenden, muss ein Auto die Entfernung des Rennens fahren können.
Das bedeutet, dass seine Batterie nicht leer sein darf, bevor es die Ziellinie überquert hat.
Implementiere die Funktion CanFinish, die eine Car- und eine Track-Instanz als Parameter entgegennimmt und true zurückgibt, wenn das Auto das Rennen beenden kann; andernfalls gibt sie false zurück.
Geh davon aus, dass du dich gerade an der Startlinie des Rennens befindest und den Motor des Autos für das Rennen startest. Berücksichtige, dass die Batterie des Autos beim Start des Rennens nicht unbedingt vollständig geladen sein muss:
speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
distance := 100
track := NewTrack(distance)
CanFinish(car, track)
// => true
Melde dich bei Exercism an, um Go mit 34 Konzepte165 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.