Как я могу динамически заполнить структуру? - PullRequest
0 голосов
/ 06 января 2020

Я хочу динамически заполнить мою внутреннюю структуру для атома c вставки. Я новичок в go, поэтому указатели и ссылки на них - это то, что я все еще изучаю. Я не могу понять, почему это для каждого l oop ставит одинаковые поля в два раза. Я попытался удалить '&', затем я получил сообщение об отсутствии типа как ошибка типа *, я проверил, что мой l oop поражает каждый объект в tradeArray, и это так. Похоже, что он перезаписывает объект перед последним циклом. Как я могу это исправить?

   func createTrade(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")

        var tradeArray []Trade


        if err := json.NewDecoder(r.Body).Decode(&tradeArray); err != nil {
            e := Error{Message: "Bad Request - Improper Types Passed"}
            w.WriteHeader(http.StatusBadRequest)
            _ = json.NewEncoder(w).Encode(e)
            return
        }


        for _, trade := range tradeArray {
            internal := InternalTrade{
                Id: strconv.Itoa(rand.Intn(1000000)),
                Trade: &trade,
            }
            submit := TradeSubmitted{
                TradeId:       internal.Id,
                ClientTradeId: trade.ClientTradeId ,
            }
            submitArray = append(submitArray, submit)
            trades = append(trades, internal)
        }


        if err := json.NewEncoder(w).Encode(submitArray); err != nil {
            e := Error{Message:"Internal Server Error"}
            w.WriteHeader(http.StatusInternalServerError)
            _ = json.NewEncoder(w).Encode(e)
            return
        }

    }

edit: я смог исправить свою проблему, создав новую переменную для хранения сделки и ссылаясь на эту переменную при создании структуры. Я не уверен, насколько это отличается от того, что я делал выше, просто ссылаясь на «сделку», если кто-то может объяснить, что я был бы очень признателен.

    for _, trade := range tradeArray {
    p := trade
    internal := InternalTrade{
        Id: strconv.Itoa(rand.Intn(1000000)),
        Trade: &p,
    }
    submit := TradeSubmitted{
        TradeId:       internal.Id,
        ClientTradeId: trade.ClientTradeId ,
    }
    submitArray = append(submitArray, submit)
    trades = append(trades, internal)
}

1 Ответ

2 голосов
/ 06 января 2020

Давайте рассмотрим только эти части:

    var tradeArray []Trade

    // code that fills in `tradeArray` -- correct, and omitted here

    for _, trade := range tradeArray {
        internal := InternalTrade{
            Id: strconv.Itoa(rand.Intn(1000000)),
            Trade: &trade,
        }
        submit := TradeSubmitted{
            TradeId:       internal.Id,
            ClientTradeId: trade.ClientTradeId ,
        }
        submitArray = append(submitArray, submit)
        trades = append(trades, internal)
    }

Эти for l oop, как вы видели, не работают так, как вы хотите. Вот его вариант, который отчасти похож, за исключением того, что переменная trade имеет область действия, которая выходит за пределы for l oop:

    var trade Trade
    for i := range tradeArray {
        trade = tradeArray[i]
        internal := InternalTrade{
            Id: strconv.Itoa(rand.Intn(1000000)),
            Trade: &trade,
        }
        // do correct stuff with `internal`
    }

Обратите внимание, что каждый объект internal указывает на одиночная общая переменная trade, значение которой перезаписывается при каждой поездке через l oop. В результате все они указывают на один из последнего путешествия через l oop.

Ваше исправление само по себе нормально: каждое путешествие через l oop вы делаете переменную new (другую) p и используйте &p, чтобы у каждого internal.Trade был свой указатель на свою копию. Вы также можете просто сделать trade := trade внутри l oop, чтобы создать новую уникальную переменную trade. Тем не менее, в этом конкретном случае, возможно, имеет смысл переписать l oop следующим образом:

    for i := range tradeArray {
        internal := InternalTrade{
            Id: strconv.Itoa(rand.Intn(1000000)),
            Trade: &tradeArray[i],
        }
        // do correct stuff with `internal`
    }

То есть у вас уже есть len(tradeArray) различные Trade объекты: заголовок слайса tradeArray предоставляет вам доступ к каждому экземпляру tradeArray[i], хранящемуся в базовом массиве. Вы можете просто указать на них напрямую.

У этого подхода есть свои преимущества и недостатки. Большим преимуществом является то, что вы не переписываете каждую сделку вообще: вы просто используете те из массива, который охватывает заголовок слайса, который был размещен внутри функции json Decode. Большим недостатком является то, что этот базовый массив нельзя собирать, пока вы сохраняете любой указатель на любой его элементов. Этот недостаток может вообще не иметь стоимости, в зависимости от структуры оставшегося кода, но если он является недостатком, рассмотрите объявление tradeArray как:

var tradeArray []*Trade

, чтобы Функция json Decode распределяет каждую из них по отдельности, и вы можете указывать на них по одной, не форсируя сохранение всей коллекции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...