Grundlagen von Zeigern in Go
Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy. Lektion 19 von 107.
Ein Zeiger ist eine Variable, die die Speicheradresse einer anderen Variable speichert. Anstatt einen Wert direkt zu enthalten, enthält er den Speicherort, an dem dieser Wert im Speicher liegt. Zeiger sind grundlegend für Go und unerlässlich für eine effiziente Datenmanipulation.
Um einen Zeiger zu erstellen, verwende den Operator &, um die Adresse einer Variable abzurufen, und den Operator *, um einen Zeigertyp zu deklarieren oder auf den Wert an dieser Adresse zuzugreifen.
x := 42
p := &x // p hält die Speicheradresse von x
fmt.Println(p) // 0xc000018030 (Speicheradresse)
fmt.Println(*p) // 42 (Wert an dieser Adresse)Der Operator & bedeutet „Adresse von“ und gibt einen Zeiger zurück. Der Operator * bedeutet bei Verwendung mit einem Zeiger „Wert an“ und wird als Dereferenzierung bezeichnet. Du kannst den ursprünglichen Wert auch über den Zeiger ändern.
x := 10
p := &x
*p = 25 // Wert über Zeiger ändern
fmt.Println(x) // 25 (ursprüngliche Variable geändert)Der Zeigertyp wird als *T geschrieben, wobei T der Typ ist, auf den gezeigt wird. Ein Zeiger auf ein int hat den Typ *int.
var p *int // deklariert einen Zeiger auf int
x := 100
p = &x // p zeigt jetzt auf xDer Nullwert eines pointer ist nil, was bedeutet, dass er auf nichts zeigt. Der Versuch, einen nil pointer zu dereferenzieren, verursacht eine Laufzeit-Panik. Stelle daher immer sicher, dass pointer vor der Verwendung initialisiert sind.
Aufgabe
EinfachErstellen wir einen einfachen Werteaustauscher, der die Leistungsfähigkeit von Zeigern demonstriert, um Variablen über ihre Speicheradressen zu verändern.
Du wirst deinen Code auf zwei Dateien verteilen:
swap.go: Erstelle eine Funktion namensSwapValues, die zwei*int-Zeiger als Parameter entgegennimmt. Diese Funktion soll die Werte vertauschen, auf die diese Zeiger zeigen. Nach dem Aufruf soll jede Variable den ursprünglichen Wert der jeweils anderen Variable enthalten. Die Funktion gibt nichts zurück; sie verändert die Werte direkt über die Zeiger.main.go: Lies zwei Ganzzahlen aus der Eingabe ein, speichere sie in Variablen und verwende dann deine FunktionSwapValues, um ihre Werte auszutauschen. Gib beide Werte vor und nach dem Austausch aus, um die Änderung zu zeigen.
Die folgenden Eingaben werden bereitgestellt:
- Zeile 1: Erste Ganzzahl
- Zeile 2: Zweite Ganzzahl
Ausgabeformat:
Before: a=[first] b=[second]
After: a=[first] b=[second]Wenn beispielsweise 10 und 25 gegeben sind, sollte deine Ausgabe folgendermaßen aussehen:
Before: a=10 b=25
After: a=25 b=10Denke daran, den Operator & zu verwenden, wenn du deine Variablen an die Funktion übergibst, und den Operator * innerhalb der Funktion, um auf die tatsächlichen Werte zuzugreifen und sie zu verändern.
Probier es selbst
package main
import "fmt"
func main() {
// Zwei Ganzzahlen von der Eingabe lesen
var a, b int
fmt.Scanln(&a)
fmt.Scanln(&b)
// Werte vor dem Tausch ausgeben
fmt.Printf("Before: a=%d b=%d\n", a, b)
// TODO: Rufe die SwapValues-Funktion mit Zeigern auf a und b auf
// Denke daran, den &-Operator zu verwenden, um Adressen zu übergeben
// Werte nach dem Tausch ausgeben
fmt.Printf("After: a=%d b=%d\n", a, b)
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP in Go
Externe DateienGo-Workspace & ModulePackages & ImportsExportierte vs. nicht exportierte NamenEinführung in OOP mit GoStructs als KlassenMethoden für Structs definierenPointer- vs. Value-ReceiverStruct-InitialisierungKonstruktorfunktionenRückblick – Einfacher Taschenrechner4Schnittstellen
Einführung in SchnittstellenImplizite ImplementierungSchnittstelle als VertragLeere Schnittstelle (any)TypzusicherungTypwechselZusammensetzung von SchnittstellenStringer- und Error-SchnittstellenRückblick – Formenrechner7Kapselung
Exportierte vs. nicht exportierte FelderKapselung auf PaketebeneGetter- und Setter-MethodenInformationsverbergung in GoRückblick – Studierendendatensätze10Generics (Go 1.18+)
Einführung in GenericsTypparameterTypbeschränkungenGenerische StrukturenWorkaround für generische MethodenZusammenfassung – Generische Sammlung2Typen & Structs im Detail
Grundlegende & zusammengesetzte TypenBenutzerdefinierte TypdefinitionenStruct-TagsAnonyme StructsVerschachtelte StructsNullwerte & StandardwerteRückblick – Kontaktbuch5Komposition statt Vererbung
Warum Go keine Vererbung hatGrundlagen der Struct-EinbettungMethoden-PromotionMehrere Structs einbettenEinbettung vs. AggregationVerbergen eingebetteter MethodenRückblick – Mitarbeiterhierarchie8Fehlerbehandlung & OOP
Das Error-InterfaceBenutzerdefinierte FehlertypenError-Wrapping (fmt.Errorf)Sentinel-Fehlererrors.Is() und errors.As()Panic, Defer und RecoverRückblick – Dateiparser3Zeiger & Speicher
Grundlagen von Zeigern in GoZeiger auf StructsÜbergabe per Wert vs. ReferenzDie Funktion new()Garbage Collection in GoRückblick – Verkettete Liste erstellen6Polymorphismus in Go
Polymorphismus über InterfacesDuck-Typing in GoRegeln zur Interface-ErfüllungPolymorphe SammlungenDependency InjectionZusammenfassung – Zahlungsprozessor9Konkurrenz & OOP
Grundlagen der GoroutinesChannels & KommunikationGepufferte vs. ungepufferte ChannelsSelect-Anweisungsync.Mutex & sync.RWMutexsync.WaitGroupThread-sicheres Struct-DesignRückblick – Worker PoolÜbe selbstständig: Online-Go-Compiler