Die Go Language Specification ( Adreßoperatoren ) erlaubt nicht die Adresse einer numerischen Konstante zu nehmen (nicht von einem nicht typisiert noch eine typisierten Konstante).
Der Operand muss adressierbar sein , dh entweder eine Variable, eine Zeiger-Indirektion oder eine Slice-Indizierungsoperation. oder ein Feldselektor eines adressierbaren Strukturoperanden; oder eine Array-Indizierungsoperation eines adressierbaren Arrays. Als Ausnahme von der Adressierbarkeitsanforderung kann x
[im Ausdruck von &x
] auch ein (möglicherweise in Klammern gesetztes) zusammengesetztes Literal sein .
Gründe, warum dies nicht zulässig ist, finden Sie in der entsprechenden Frage: Suchen Sie die Adresse der Konstanten in go . Eine ähnliche Frage (die ebenfalls keine Adresse annehmen darf): Wie kann ich einen Verweis auf das Ergebnis einer Operation in Go speichern?
Ihre Optionen (probieren Sie alle auf dem Go-Spielplatz aus ):
1) Mit new()
Sie können einfach die eingebaute new()
Funktion verwenden, um einen neuen Nullwert zuzuweisen int64
und seine Adresse zu erhalten:
instance := SomeType{
SomeField: new(int64),
}
Beachten Sie jedoch, dass dies nur verwendet werden kann, um einen Zeiger auf den Nullwert eines beliebigen Typs zuzuweisen und zu erhalten.
2) Mit Hilfsvariable
Am einfachsten und empfehlenswert für Elemente ungleich Null ist die Verwendung einer Hilfsvariablen, deren Adresse verwendet werden kann:
helper := int64(2)
instance2 := SomeType{
SomeField: &helper,
}
3) Mit Hilfsfunktion
Hinweis: Hilfsfunktionen zum Erfassen eines Zeigers auf einen Wert ungleich Null sind in meiner github.com/icza/gox
Bibliothek im gox
Paket verfügbar , sodass Sie diese nicht zu allen Ihren Projekten hinzufügen müssen, wo Sie sie benötigen.
Wenn Sie dies mehrmals benötigen, können Sie eine Hilfsfunktion erstellen, die Folgendes zuweist und zurückgibt *int64
:
func create(x int64) *int64 {
return &x
}
Und damit:
instance3 := SomeType{
SomeField: create(3),
}
Beachten Sie, dass wir tatsächlich nichts zugewiesen haben. Der Go-Compiler hat dies getan, als wir die Adresse des Funktionsarguments zurückgegeben haben. Der Go-Compiler führt eine Escape-Analyse durch und weist dem Heap (anstelle des Stacks) lokale Variablen zu, wenn sie der Funktion entkommen können. Weitere Informationen finden Sie unter Ist die Rückgabe eines Slice eines lokalen Arrays in einer Go-Funktion sicher?
4) Mit einer einzeiligen anonymen Funktion
instance4 := SomeType{
SomeField: func() *int64 { i := int64(4); return &i }(),
}
Oder als (kürzere) Alternative:
instance4 := SomeType{
SomeField: func(i int64) *int64 { return &i }(4),
}
5) Mit Slice-Literal, Indizierung und Adressierung
Wenn Sie *SomeField
anders sein möchten als 0
, dann brauchen Sie etwas Adressierbares.
Sie können das immer noch tun, aber das ist hässlich:
instance5 := SomeType{
SomeField: &[]int64{5}[0],
}
fmt.Println(*instance2.SomeField) // Prints 5
Was hier passiert, ist, dass ein []int64
Slice mit einem Literal erstellt wird, das ein Element ( 5
) enthält. Und es wird indiziert (0. Element) und die Adresse des 0. Elements wird genommen. Im Hintergrund [1]int64
wird auch ein Array von zugewiesen und als Hintergrundarray für das Slice verwendet. Hier gibt es also viel Boilerplate.
6) Mit einem Hilfsstrukturliteral
Lassen Sie uns die Ausnahme von den Adressierbarkeitsanforderungen untersuchen:
Als Ausnahme von der Adressierbarkeitsanforderung kann x
[im Ausdruck von &x
] auch ein (möglicherweise in Klammern gesetztes) zusammengesetztes Literal sein .
Dies bedeutet, dass es in Ordnung ist, die Adresse eines zusammengesetzten Literal zu übernehmen, z. B. eines Strukturliterals. Wenn wir dies tun, wird uns der Strukturwert zugewiesen und ein Zeiger darauf erhalten. In diesem Fall steht uns jedoch eine weitere Anforderung zur Verfügung: "Feldauswahl eines adressierbaren Strukturoperanden" . Wenn das Strukturliteral also ein Feld vom Typ enthält int64
, können wir auch die Adresse dieses Feldes übernehmen!
Lassen Sie uns diese Option in Aktion sehen. Wir werden diesen Wrapper-Strukturtyp verwenden:
type intwrapper struct {
x int64
}
Und jetzt können wir tun:
instance6 := SomeType{
SomeField: &(&intwrapper{6}).x,
}
Beachten Sie, dass dies
&(&intwrapper{6}).x
bedeutet folgendes:
& ( (&intwrapper{6}).x )
Wir können jedoch die "äußere" Klammer weglassen, da der Adressoperator &
auf das Ergebnis des Selektorausdrucks angewendet wird .
Beachten Sie auch, dass im Hintergrund Folgendes passiert (dies ist auch eine gültige Syntax):
&(*(&intwrapper{6})).x
7) Mit dem anonymen Strukturliteral des Helfers
Das Prinzip ist das gleiche wie in Fall 6, wir können jedoch auch ein anonymes Strukturliteral verwenden, sodass keine Definition des Strukturtyps für Helfer / Wrapper erforderlich ist:
instance7 := SomeType{
SomeField: &(&struct{ x int64 }{7}).x,
}