[英]why json.Unmarshal change the pointer value after append a new one in golang?
我有一個問題,為什么 json.Unmarshal 在追加一個新的( test2 )之后首先更改指針值( create_at ) ( test1 )但num在 golang 中沒有變化?
json.Unmarshal 會重用地址嗎? 我不明白為什么追加一個新值(不是指針值)會影響之前插入的元素,如果我改變*time.Time -> time.Time,這個問題就會解決...
package main
import (
"bytes"
"encoding/json"
"fmt"
"time"
)
type test struct {
Num int `json:"num"`
CreateAt *time.Time `json:"create_at"`
}
func main() {
var icr []test
var res test
now := time.Now()
next := time.Now().Add(time.Hour)
test1 := test{
Num: 1,
CreateAt: &now,
}
test2 := test{
Num: 2,
CreateAt: &next,
}
newBytes := new(bytes.Buffer)
json.NewEncoder(newBytes).Encode(test1)
json.Unmarshal(newBytes.Bytes(), &res)
icr = append(icr, res)
fmt.Println(PrettyPrint(icr))
// [
// {
// "num": 1,
// "create_at": "2020-09-24T15:03:00.755169076+08:00"
// }
// ]
newBytes = new(bytes.Buffer)
json.NewEncoder(newBytes).Encode(test2)
json.Unmarshal(newBytes.Bytes(), &res)
icr = append(icr, res)
fmt.Println(PrettyPrint(icr))
// [
// {
// "num": 1,
// "create_at": "2020-09-24T16:03:00.755169556+08:00"
// },
// {
// "num": 2,
// "create_at": "2020-09-24T16:03:00.755169556+08:00"
// }
// ]
}
// PrettyPrint ...
func PrettyPrint(data interface{}) string {
var out bytes.Buffer
b, _ := json.Marshal(data)
json.Indent(&out, b, "", " ")
return out.String()
}
簡短版本:切片中的所有元素都是res
淺拷貝,因此CreateAt
字段指向相同的值。
詳情:
將res
附加到icr
,添加到icr
的元素是res
的副本。
這適用於字段Num
,它可以在res
修改而不會影響存儲在icr
的數據。 這是因為它是一個基本類型。
但是, res
的CreateAt
字段是一個指針,因此副本仍然是同一個指針。 icr
所有元素都將具有CreateAt
指向相同的值。 對該值的任何修改都將反映在icr
所有元素中。
您有兩個選擇(至少):
CreateAt
平淡time.Time
,這意味着它會被復制,而不是只是一個指針json.Unmarshal(newBytes.Bytes(), &res2)
這是一個沒有 json 或 slices 的更清晰的示例,只有兩個變量,其中一個是另一個的副本: see on playground :
package main
import (
"bytes"
"encoding/json"
"fmt"
"time"
)
type test struct {
Num int `json:"num"`
CreateAt *time.Time `json:"create_at"`
}
func main() {
now := time.Now()
res := test{1, &now}
res2 := res
fmt.Println(PrettyPrint(res), PrettyPrint(res2))
// Modify res2:
res2.Num = 2
*res2.CreateAt = time.Now().Add(time.Hour)
fmt.Println(PrettyPrint(res), PrettyPrint(res2))
}
// PrettyPrint ...
func PrettyPrint(data interface{}) string {
var out bytes.Buffer
b, _ := json.Marshal(data)
json.Indent(&out, b, "", " ")
return out.String()
}
輸出:
{
"num": 1,
"create_at": "2009-11-10T23:00:00Z"
} {
"num": 1,
"create_at": "2009-11-10T23:00:00Z"
}
{
"num": 1,
"create_at": "2009-11-11T00:00:00Z"
} {
"num": 2,
"create_at": "2009-11-11T00:00:00Z"
}
更新res2
, res2.Num
不會影響res.Num
因為它是基本類型。 但是, res2.CreateAt
和res.CreateAt
都指向同一個對象,因此更改會反映在兩者中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.