package main
import "fmt"
type beispiel struct {
x string
y string
}
func main() {
a := beispiel{"A", "A"}
b := a
b.x = "B"
fmt.Printf("%v\n", a)
fmt.Printf("%v\n", b)
// nun mit Zeigern
pa := &beispiel{"A", "A"}
pb := pa
pb.x = "B"
fmt.Printf("%v\n", pa)
fmt.Printf("%v\n", pb)
}
Zeiger (pointer)
Alle Daten (Zeichenketten, Funktionen, Structs, …) liegen im Hauptspeicher des Computers, damit das Programm darauf zugreifen kann.
Go kümmert sich um die Organisation aller Daten, ohne, dass der Benutzer das merkt oder eingreifen muss.
Weist man einer Variablen str
eine Zeichenkette zu, dann kann man sofort damit arbeiten, ohne sich um den Speicherzugriff zu kümmern.
Manchmal möchte man jedoch die Adresse der Daten haben, um diese direkt manipulieren zu können.
Im Gegensatz zu Programmiersprachen wie C kann man jedoch keine Zeigerarithmetik durchführen:
package main
import (
"fmt"
)
func main() {
a := 3
// pa ist Zeiger auf a und enthält
// die Adresse von a im Speicher
pa := &a
fmt.Println(pa)
// geht nicht:
pa++
}
Mit Zeigern kann man mit mehreren Variablen auf denselben Speicherbereich zeigen. Damit kann man den Speicher von mehreren Stellen aus verändern und mit allen Variablen kann man auf die veränderten Werte zugreifen:
main()
Funktion wird ein Kopie der Struktur erzeugt und an b
zugewiesen. In der Zuweisung pb := pa
wird eine Kopie des Zeigers erzeugt, beide Variablen zeigen auf dieselbe Stelle.Eine Erklärung der Zeichen: &x
bedeutet »Speicheradresse von x
«. &beispiel{...}
bedeutet dasselbe wie &(beispiel{..})
und ist im Prinzip eine Kurzform für
tmp : = beispiel{...}
b := &tmp
nur ohne eine temporäre Variable.
Es wird also die Speicheradresse einer Instanz der Struktur beispiel
zurückgegeben.
Zeiger können auch den Wert nil
haben, dann darf man sie nicht benutzen.
Die Speicheradresse gibt es nicht und damit keinen Wert, den man dort abfragen kann.
Daher ist es oft wichtig, auf nil
zu prüfen.
package main
import "fmt"
type beispiel struct {
x string
y string
}
func main() {
var pb *beispiel
fmt.Println(pb)
pb.x = "test"
}
pb
ist noch nicht initialisiert, daher hat der Zeiger den Wert nil
. Greift man nun auf ein Feld innerhalb der Struktur zu, gibt es einen Laufzeitfehler.Die Ausgabe aus dem Programm (go run main.go
) ist:
<nil>
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x10a6ef8]
goroutine 1 [running]:
main.main()
/home/gobuch/main.go:13 +0x78
exit status 2
Auf nil
zu prüfen ist leicht:
package main
import (
"log"
)
type beispiel struct {
x string
y string
}
func main() {
var pb *beispiel
// zum Testen die nächste Zeile mit // auskommentieren
pb = new(beispiel)
if pb == nil {
// beendet das Programm mit einem Fehler
log.Fatal("pb wurde nicht initialisiert")
}
pb.x = "test"
}