Mam typ struktury z *int64
polem.
type SomeType struct {
SomeField *int64
}
W pewnym momencie w moim kodzie chcę zadeklarować literał tego (powiedzmy, kiedy wiem, że wspomniana wartość powinna wynosić 0 lub wskazująca na 0, wiesz, o co mi chodzi)
instance := SomeType{
SomeField: &0,
}
... poza tym, że to nie działa
./main.go:xx: cannot use &0 (type *int) as type *int64 in field value
Więc próbuję tego
instance := SomeType{
SomeField: &int64(0),
}
... ale to też nie działa
./main.go:xx: cannot take the address of int64(0)
Jak mam to zrobic? Jedynym rozwiązaniem, które mogę wymyślić, jest użycie zmiennej zastępczej
var placeholder int64
placeholder = 0
instance := SomeType{
SomeField: &placeholder,
}
Uwaga: Edycja: nie, nie. Przepraszam za to.&0
składnia działa dobrze, gdy jest to * int zamiast *int64
.
Edytować:
Najwyraźniej moje pytanie było zbyt wieloznaczne. Szukam sposobu na dosłownie państwowej A *int64
. Można tego użyć wewnątrz konstruktora lub do określenia wartości struktury literału, a nawet jako argumenty innych funkcji. Ale funkcje pomocnicze lub używanie innego typu nie są rozwiązaniami, których szukam.
var _ *int64 = pointer.Int64(64)
Odpowiedzi:
Specyfikacja języka Go ( operatory adresu ) nie pozwala na przyjęcie adresu stałej numerycznej (nie bez typu ani stałej wpisanej ).
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, wgox
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) // Prints 5
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:
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, }
źródło
instance
dwa różne obiekty wskazywałyby na dwa różneint64
s. Ale wydaje się, że odpowiednio spełnia intencje OP&[]int64{2}[0]
czuję, że na podstawie opisu stałych na blog.golang.org/constants powinno to działać tak, jak&0
.instance
obiekty wskazywały na ten samint64
i jeden zmodyfikowałby wskazany obiekt, oba uległyby zmianie. A co, jeśli teraz użyjesz tego samego literału do utworzenia trzeciegoinstance
? Ten sam adres wskazywałby teraz na innąint64
wartość ... więc należy użyć innego adresu, ale w takim razie po co używać tego samego w przypadku pierwszych 2?Użyj funkcji, która zwraca adres zmiennej int64, aby rozwiązać problem.
type myStr struct { url *int64 } func main() { f := func(s int64) *int64 { return &s } myStr{ url: f(12345), } }
źródło