Почему обычный цикл for позволяет присваивать значение полям структуры, а диапазон for не работает в Golang?
Использование для диапазона:
for _, acc := range accounts{
accDetails, _ := repo.GetAccountDets(ctx, acc.number, acc.status)
acc.Details = *accDetails
}
Вышеупомянутый не работает.
Но работает следующее.
for i:=0; i < len(accounts); i++ {
accDetails, _ := repo.GetAccountDets(ctx, accounts[i].number, accounts[i].status)
accounts[i].Details = *accDetails
}
Это почему? Я не думаю, что добавление деталей структуры аккаунта здесь имеет какое-то значение
3 ответа
В цикле for формы for i,v:=range slice {...}
, переменная v
имеет тот же тип, что и элемент, который он перебирает, и каждая итерация копирует содержимое следующего элемента из среза / карты в v
. Так что еслиv
является структурой, и вы назначаете значения членам структуры, они никогда не копируются обратно в срез, из которого они копируются. Если фрагмент - это фрагмент указателей на структуру, тогдаv
является копией указателя на структуру, и изменения, которые вы вносите в v
Члены будут отражены в исходных элементах среза. Один из способов исправить это - использовать index:
for i:=range accounts {
accounts[i].Field=value
}
Я бы сказал, что вопрос выходит за рамки Голанга и связан с базовой структурой данных или контейнером. Во втором случае вы, кажется, уже знаете длину своего контейнера len(accounts), и, следовательно, это фиксированное хранилище, к которому можно последовательно обращаться. Так должно быть не всегда. Что, если бы учетные записи были постоянно увеличивающимся (или уменьшающимся) контейнером? Как бы вы измерили длину этого контейнера. Вместо этого все, что вы просите, это то, что есть в "аккаунтах", просто дайте мне это. Как ты собираешься это сделать? Итак, вы настроили фиктивную переменную, которой разрешен только доступ или имитация содержимого вашего контейнера (и, следовательно, она несет с собой все атрибуты или "поля структуры"). Кроме того, его можно было бы использовать в следующем коде,с учетом области действия, только для чтения.
Всякий раз, когда вы инициализируете переменную в цикле for, эта переменная локально ограничена только циклом for, в диапазоне вы создадите копию элемента в переменной acc
for _, acc := range accounts{
accDetails, _ := repo.GetAccountDets(ctx, acc.number, acc.status)
acc.Details = *accDetails
}
acc - это просто локальная копия элементов в учетных записях, она не повлияет на срез учетных записей, если вы добавите что-нибудь в acc.
Но в другом твоем примере..
for i:=0; i < len(accounts); i++ {
accDetails, _ := repo.GetAccountDets(ctx, accounts[i].number, accounts[i].status)
accounts[i].Details = *accDetails
}
Вы не делаете локальную копию для элементов в учетных записях, вместо этого вы напрямую получаете к ним доступ через учетные записи [i], это обновит срез учетных записей.
Если вы все еще хотите использовать диапазон, вы можете использовать только индекс.
for i := range accounts{
accDetails, _ := repo.GetAccountDets(ctx, accounts[i].number, accounts[i].status)
accounts[i].Details = *accDetails
}