Предположим, у меня есть эти типы:
type Attribute struct {
Key, Val string
}
type Node struct {
Attr []Attribute
}
и что я хочу перебрать атрибуты моего узла, чтобы изменить их.
Я хотел бы иметь возможность сделать:
for _, attr := range n.Attr {
if attr.Key == "href" {
attr.Val = "something"
}
}
но, как attr
не указатель, это не будет работать, и я должен сделать:
for i, attr := range n.Attr {
if attr.Key == "href" {
n.Attr[i].Val = "something"
}
}
Есть ли более простой или быстрый способ? Можно ли напрямую получить указатели от range
?
Очевидно, я не хочу менять структуры только для итерации, и более подробные решения не являются решениями.
Array.prototype.forEach
в JavaScript?forEach
должна начинаться с утверждения типа. Это не совсем лучше, чемattr := &n.Attr[i]
.Ответы:
Нет, аббревиатура, которую вы хотите, невозможна.
Причиной этого является то, что
range
копирует значения из фрагмента, который вы перебираете. Спецификация о диапазоне говорит:Таким образом, диапазон использует в
a[i]
качестве второго значения для массивов / слайсов, что фактически означает, что значение копируется, что делает исходное значение неприкосновенным.Это поведение демонстрируется следующим кодом :
Код печатает вам абсолютно разные области памяти для значения из диапазона и фактического значения в срезе:
Поэтому единственное, что вы можете сделать, это использовать указатели или индекс, как это уже предложено jnml и peterSO.
источник
a[i]
цикл from от цикла for,a[i]
как мы пишем? Похоже, то же самое, но это не так, верно?range
возвращается вa[i]
качестве второго возвращаемого значения. Эта операция,val = a[i]
как и при выполнении,range
создает копию значения, поэтому любая операция записи вval
нее применяется к копии.Вы, кажется, просите что-то эквивалентное этому:
Вывод:
Это позволяет избежать создания (возможно, большой) копии
Attribute
значений типов за счет проверки границ слайсов. В вашем примере типAttribute
относительно небольшой, двеstring
ссылки на слайсы: 2 * 3 * 8 = 48 байт на машине с 64-битной архитектурой.Вы также можете просто написать:
Но способ получить эквивалентный результат с помощью
range
предложения, которое создает копию, но сводит к минимуму проверки границ слайса, заключается в следующем:источник
value := &someMap[key]
не получится, еслиsomeMap
этоmap
*attr.Val = "something"
Я бы адаптировал ваше последнее предложение и использовал бы индексную версию диапазона.
Мне кажется проще ссылаться в
n.Attr[i]
явной форме как на строку, которая проверяет, такKey
и на строку, которая устанавливаетVal
, вместо того, чтобы использоватьattr
для одного иn.Attr[i]
для другого.источник
Например:
Игровая площадка
Вывод
Альтернативный подход:
Игровая площадка
Вывод:
источник
go.net/html
пакета)