Załóżmy, że mam te typy:
type Attribute struct {
Key, Val string
}
type Node struct {
Attr []Attribute
}
i że chcę iterować na atrybutach mojego węzła, aby je zmienić.
Bardzo chciałbym móc:
for _, attr := range n.Attr {
if attr.Key == "href" {
attr.Val = "something"
}
}
ale ponieważ attr
nie jest wskaźnikiem, to nie zadziała i muszę zrobić:
for i, attr := range n.Attr {
if attr.Key == "href" {
n.Attr[i].Val = "something"
}
}
Czy jest prostszy lub szybszy sposób? Czy można bezpośrednio uzyskać wskazówki range
?
Oczywiście nie chcę zmieniać struktur tylko dla iteracji, a bardziej szczegółowe rozwiązania nie są rozwiązaniami.
Array.prototype.forEach
w JavaScript?forEach
typów ogólnych, obawiam się, że funkcja przekazana do musi zaczynać się od asercji typu. To nie jest lepsze niżattr := &n.Attr[i]
.Odpowiedzi:
Nie, żądany skrót nie jest możliwy.
Powodem tego jest to, że
range
kopiuje wartości z wycinka, po którym iterujesz. Specyfikacja o zasięgu mówi:Tak więc zakres jest używany
a[i]
jako druga wartość dla tablic / plasterków, co skutecznie oznacza, że wartość jest kopiowana, co sprawia, że oryginalna wartość jest nietykalna.To zachowanie jest przedstawione w następującym kodzie :
Kod drukuje całkowicie różne lokalizacje pamięci dla wartości z zakresu i rzeczywistej wartości w wycinku:
Więc jedyne, co możesz zrobić, to użyć wskaźników lub indeksu, co zostało już zaproponowane przez jnml i peterSO.
źródło
a[i]
się pętla z pętli for od pętli w chwili,a[i]
gdy piszemy? Wygląda na to samo, ale tak nie jest, prawda?range
zwracaa[i]
jako drugą wartość zwracaną. Ta operacja,val = a[i]
tak jak została wykonana przez,range
tworzy kopię wartości, więc każda operacja zapisuval
jest stosowana do kopii.Wydaje się, że prosisz o coś równoważnego z tym:
Wynik:
Pozwala to uniknąć tworzenia - być może dużej - kopii
Attribute
wartości typu kosztem sprawdzania granic wycinków. W twoim przykładzie typAttribute
jest stosunkowo mały,string
odwołania do dwóch wycinków: 2 * 3 * 8 = 48 bajtów na komputerze o architekturze 64-bitowej.Możesz też po prostu napisać:
Ale sposobem na uzyskanie równoważnego wyniku z
range
klauzulą, która tworzy kopię, ale minimalizuje sprawdzanie granic wycinków, jest:źródło
value := &someMap[key]
nie zadziała, jeślisomeMap
jestmap
*attr.Val = "something"
Dostosowałbym twoją ostatnią sugestię i użył tylko indeksowanej wersji zakresu.
Wydaje mi się, że prostsze jest odwoływanie się
n.Attr[i]
bezpośrednio zarówno do wiersza, który testuje, jakKey
i do wiersza, który ustawiaVal
, zamiast używaćattr
dla jednego in.Attr[i]
drugiego.źródło
Na przykład:
Plac zabaw
Wynik
Alternatywne podejście:
Plac zabaw
Wynik:
źródło
go.net/html
paczki)