[英]why json.Unmarshal change the pointer value after append a new one in golang?
I have a question about why json.Unmarshal change the pointer value (create_at) first ( test1 ) after append a new one ( test2 ) but num is dont change in golang ?我有一个问题,为什么 json.Unmarshal 在追加一个新的( test2 )之后首先更改指针值( create_at ) ( test1 )但num在 golang 中没有变化?
json.Unmarshal will reuse the address ? json.Unmarshal 会重用地址吗? I don't understand why append a new value (don't pointer value) will influences the elements insert before, if I change the *time.Time -> time.Time, this problem will be solve...
我不明白为什么追加一个新值(不是指针值)会影响之前插入的元素,如果我改变*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()
}
The short version : all elements in your slice are shallow copies of res
, so the CreateAt
field points to the same value.简短版本:切片中的所有元素都是
res
浅拷贝,因此CreateAt
字段指向相同的值。
Details :详情:
When appending res
to icr
, the element added to icr
is a copy of res
.将
res
附加到icr
,添加到icr
的元素是res
的副本。
This works fine for the field Num
, it can be modified in res
without impacting the data stored in icr
.这适用于字段
Num
,它可以在res
修改而不会影响存储在icr
的数据。 This is because it's a base type.这是因为它是一个基本类型。
However, the CreateAt
field of res
is a pointer , so the copy is still the same pointer.但是,
res
的CreateAt
字段是一个指针,因此副本仍然是同一个指针。 All elements of icr
will have CreateAt
point to the same value. icr
所有元素都将具有CreateAt
指向相同的值。 Any modification of that value will be reflected in all elements of icr
.对该值的任何修改都将反映在
icr
所有元素中。
You have two options (at least):您有两个选择(至少):
CreateAt
to plain time.Time
, meaning it will be copied and not just a pointerCreateAt
平淡time.Time
,这意味着它会被复制,而不是只是一个指针json.Unmarshal(newBytes.Bytes(), &res2)
json.Unmarshal(newBytes.Bytes(), &res2)
Here is a clearer example without json or slices, just two variables one of which is a copy of the other: see on playground :这是一个没有 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()
}
Output:输出:
{
"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"
}
When updating res2
, the res2.Num
does not impact res.Num
since it is a base type.更新
res2
, res2.Num
不会影响res.Num
因为它是基本类型。 However, res2.CreateAt
and res.CreateAt
both point to the same object so the change is reflected in both.但是,
res2.CreateAt
和res.CreateAt
都指向同一个对象,因此更改会反映在两者中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.