I've been working on a hobby project and have gotten to the point where I need to differentiate between an initialized zero value, and an intentional zero value for any partial update capable requests. After a lot of reading, I went with the route of making all of my incoming struct fields pointers. Since pointers initialize to nil, and the JSON marshaller binds zero values, it lets me make that distinguishment. I started sending some API requests over, and was seeing what I expect at first, results looking like:
{0xc00058e240 <nil>}
When I added a time.Time field to the struct though, and sent a timestamp over, I see this:
{0xc0004060d0 <nil> 2004-10-16 00:00:00 0000 UTC}
I would have expected the timestamp to also be a pointer to some memory location. I tested a little more with the methods below, and it still prints a timestamp. I was under the impression if you tried to use *variable
in an operation, it would throw an error for you. The code below works as expected, so it's like time.Time is a pointer even though it prints right from the struct in its normal format.
type updateTestRequest struct {
TestString *string `json:"test_string" binding:"alphanum"`
TestName *string `json:"test_name,omitempty"`
TestTime *time.Time `json:"test_time" time_format:"2006-01-02" binding:"required"`
}
func (server *Server) updateTest(ctx *gin.Context) {
var req updateUserRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(http.StatusBadRequest, errorResponse(err))
return
}
fmt.Printf("%v", req)
if req.TestTime != nil {
fmt.Printf("value: '%v'", *req.TestTime)
} else {
println("it was nil.")
}
}
{
"test_string":"Testing",
"first_name": "",
"date_of_birth": "2004-10-16T00:00:00.00Z"
}
I'm still pretty new to Golang, so it could be my misunderstanding of the language. Why does timestamp not print out as a memory address like the other pointers?
CodePudding user response:
The time package documentation shows that time.Time has a String() string
method. Because the pointer receiver method set includes the value receiver methods, a *time.Time also has a String() string
method.
The fmt package documentation says:
If the format (which is implicitly %v for Println etc.) is valid for a string (%s %q %v %x %X), the following two rules apply:
- If an operand implements method
String() string
, that method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any).
It follows that the *time.Time is displayed using the result of the time's String() method.