Zeiger sind aus mehreren Gründen nützlich. Zeiger ermöglichen die Kontrolle über das Speicherlayout (wirkt sich auf die Effizienz des CPU-Cache aus). In Go können wir eine Struktur definieren, in der sich alle Mitglieder im zusammenhängenden Speicher befinden:
type Point struct {
x, y int
}
type LineSegment struct {
source, destination Point
}
In diesem Fall sind die Point
Strukturen in die Struktur eingebettet LineSegment
. Sie können Daten jedoch nicht immer direkt einbetten. Wenn Sie Strukturen wie Binärbäume oder verknüpfte Listen unterstützen möchten, müssen Sie eine Art Zeiger unterstützen.
type TreeNode {
value int
left *TreeNode
right *TreeNode
}
Java, Python usw. haben dieses Problem nicht, da Sie keine zusammengesetzten Typen einbetten können, sodass syntaktisch nicht zwischen Einbetten und Zeigen unterschieden werden muss.
Probleme mit Swift / C # -Strukturen, die mit Go-Zeigern behoben wurden
Eine mögliche Alternative, um dasselbe zu erreichen, besteht darin, zwischen struct
und class
wie C # und Swift zu unterscheiden. Dies hat jedoch Einschränkungen. Während Sie normalerweise angeben können, dass eine Funktion eine Struktur alsinout
Parameter verwendet, um das Kopieren der Struktur zu vermeiden, können Sie keine Verweise (Zeiger) auf Strukturen speichern. Dies bedeutet, dass Sie eine Struktur niemals als Referenztyp behandeln können, wenn Sie dies nützlich finden, z. B. um einen Pool-Allokator zu erstellen (siehe unten).
Benutzerdefinierter Speicherzuweiser
Mithilfe von Zeigern können Sie auch Ihren eigenen Pool-Allokator erstellen (dies ist sehr vereinfacht, da viele Überprüfungen entfernt wurden, um nur das Prinzip zu zeigen):
type TreeNode {
value int
left *TreeNode
right *TreeNode
nextFreeNode *TreeNode; // For memory allocation
}
var pool [1024]TreeNode
var firstFreeNode *TreeNode = &pool[0]
func poolAlloc() *TreeNode {
node := firstFreeNode
firstFreeNode = firstFreeNode.nextFreeNode
return node
}
func freeNode(node *TreeNode) {
node.nextFreeNode = firstFreeNode
firstFreeNode = node
}
Tauschen Sie zwei Werte aus
Mit Zeigern können Sie auch implementieren swap
. Das heißt, die Werte zweier Variablen werden ausgetauscht:
func swap(a *int, b *int) {
temp := *a
*a = *b
*b = temp
}
Fazit
Java war nie in der Lage, C ++ für die Systemprogrammierung an Orten wie Google vollständig zu ersetzen, auch weil die Leistung nicht in gleichem Maße angepasst werden kann, da das Speicherlayout und die Speicherauslastung nicht gesteuert werden können (Cache-Fehler beeinträchtigen die Leistung erheblich). Go hat sich zum Ziel gesetzt, C ++ in vielen Bereichen zu ersetzen und muss daher Zeiger unterstützen.