go - 如何动态填充结构?
问题描述
我想动态填充我的内部结构,用于原子插入。我是新手,所以指针和引用它们是我仍在学习的东西。我不明白为什么每个循环都将相同的字段放入两次。我尝试删除'&'然后我得到一个不能使用类型作为*类型的错误,我检查以确保我的循环击中了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
}
}
编辑:我能够通过创建一个新变量来保存交易并在结构创建中引用该变量来解决我的问题。如果有人能解释说我将不胜感激,我不确定这与我在上面所做的仅引用“交易”有何不同。
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)
}
解决方案
让我们看看这些部分:
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
如您所见,此循环不会按您想要的方式工作。这是它的一个变体,它有点相似,只是变量trade
的范围超出了for
循环:
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
变量,其值在每次循环时都会被覆盖。结果是它们都指向最后一次循环中的那个。
您的修复本身是可以的:每次循环遍历,您创建一个新的(不同的)p
变量,并使用&p
,以便每个internal.Trade
都有一个指向不同副本的不同指针。您也可以trade := trade
在循环内执行,以创建一个新的唯一trade
变量。但是,在这种特殊情况下,以这种方式重写循环可能最有意义:
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
函数会分别分配每一个,并且您可以一次指向它们一个,而不会强制保留整个集合。
推荐阅读
- apache-spark - 在 Windows 上使用 pyspark 不起作用-py4j
- php - 在 Woocommerce 3.2+ 中以编程方式向订单添加折扣
- html - 将图像放在另一个图像上并保持比例(HTML - CSS)
- php - 如何使用laravel制作带有特殊字符的密码
- arrays - 如何使用高阶函数获得对角线的总和?
- ssis - 从excel文件加载数据的SSIS问题
- excel - 从外部 vbs 运行时宏的行为不同
- java - 从 Java 中的 Tableau 仪表板中捕获表数据
- linux - tcpdump http 请求/响应 Wireshark
- .net - 获取struct的方法表