Specyfikacja języka Go ( operatory adresu ) nie pozwala na przyjęcie adresu stałej numerycznej (nie bez typu ani stałej wpisanej ).
Operand musi być adresowalny , to znaczy zmienna, wskaźnik pośredni lub operacja indeksowania wycinka; lub selektor pola adresowalnego argumentu struktury; lub operacja indeksowania tablicy adresowalnej. Jako wyjątek od wymagania adresowalności, x
[w wyrażeniu &x
] może być również (prawdopodobnie umieszczonym w nawiasach) literałem złożonym .
Aby wyjaśnić, dlaczego jest to niedozwolone, zobacz powiązane pytanie: Znajdź adres stałej w ruchu . Podobne pytanie (podobnie nie można wziąć jego adresu): Jak mogę zapisać odniesienie do wyniku operacji w Go?
Twoje opcje (wypróbuj wszystkie na Go Playground ):
1) Z new()
Możesz po prostu użyć new()
funkcji wbudowanej, aby przydzielić nową wartość zerową int64
i uzyskać jej adres:
instance := SomeType{
SomeField: new(int64),
}
Należy jednak pamiętać, że można tego użyć tylko do przydzielenia i uzyskania wskaźnika do wartości zerowej dowolnego typu.
2) Ze zmienną pomocniczą
Najprostszym i zalecanym dla niezerowych elementów jest użycie zmiennej pomocniczej, której adres można pobrać:
helper := int64(2)
instance2 := SomeType{
SomeField: &helper,
}
3) Z funkcją pomocniczą
Uwaga: Funkcje pomocnicze do uzyskiwania wskaźnika do wartości niezerowej są dostępne w mojej github.com/icza/gox
bibliotece, w gox
pakiecie, więc nie musisz ich dodawać do wszystkich projektów, w których jest to potrzebne.
Lub jeśli potrzebujesz tego wiele razy, możesz utworzyć funkcję pomocniczą, która przydziela i zwraca *int64
:
func create(x int64) *int64 {
return &x
}
I używając go:
instance3 := SomeType{
SomeField: create(3),
}
Zauważ, że w rzeczywistości niczego nie alokowaliśmy, kompilator Go zrobił to, kiedy zwróciliśmy adres argumentu funkcji. Kompilator Go wykonuje analizę ucieczki i przydziela zmienne lokalne na stercie (zamiast na stosie), jeśli mogą one uciec przed funkcją. Aby uzyskać szczegółowe informacje, zobacz Czy zwracanie wycinka tablicy lokalnej w funkcji Go jest bezpieczne?
4) Z jedną linijką anonimową funkcją
instance4 := SomeType{
SomeField: func() *int64 { i := int64(4); return &i }(),
}
Lub jako (krótsza) alternatywa:
instance4 := SomeType{
SomeField: func(i int64) *int64 { return &i }(4),
}
5) Z dosłownym wycinkiem, indeksowaniem i przyjmowaniem adresu
Jeśli chcesz *SomeField
być inny niż 0
, potrzebujesz czegoś adresowalnego.
Nadal możesz to zrobić, ale to brzydkie:
instance5 := SomeType{
SomeField: &[]int64{5}[0],
}
fmt.Println(*instance2.SomeField)
To, co się tutaj dzieje, to []int64
plasterek tworzony za pomocą literału, który ma jeden element ( 5
). I jest indeksowany (element zerowy) i brany jest adres elementu zerowego. W tle tablica [1]int64
zostanie również przydzielona i użyta jako tablica zapasowa dla wycinka. Jest tu więc dużo schematów.
6) Ze strukturą pomocniczą dosłownie
Przeanalizujmy wyjątek od wymagań adresowalności:
Jako wyjątek od wymagania adresowalności, x
[w wyrażeniu &x
] może być również (prawdopodobnie umieszczonym w nawiasach) literałem złożonym .
Oznacza to, że pobranie adresu literału złożonego, np. Literału struktury, jest w porządku. Jeśli to zrobimy, będziemy mieli przydzieloną wartość struktury i uzyskany do niej wskaźnik. Ale jeśli tak, stanie się dla nas dostępne inne wymaganie: „selektor pola argumentu struktury adresowalnej” . Więc jeśli literał struct zawiera pole typu int64
, możemy również wziąć adres tego pola!
Zobaczmy, jak działa ta opcja. Użyjemy tego typu struktury otoki:
type intwrapper struct {
x int64
}
A teraz możemy:
instance6 := SomeType{
SomeField: &(&intwrapper{6}).x,
}
Zauważ, że this
&(&intwrapper{6}).x
oznacza co następuje:
& ( (&intwrapper{6}).x )
Możemy jednak pominąć „zewnętrzny” nawias, ponieważ operator adresu &
jest stosowany do wyniku wyrażenia selektora .
Zwróć również uwagę, że w tle wydarzy się co następuje (jest to również poprawna składnia):
&(*(&intwrapper{6})).x
7) Z helper anonymous struct dosłownie
Zasada jest taka sama jak w przypadku # 6, ale możemy również użyć anonimowego literału struktury, więc nie jest potrzebna definicja typu helper / wrapper struct:
instance7 := SomeType{
SomeField: &(&struct{ x int64 }{7}).x,
}