0

In Go, how do you assign a value returned by a function call to a pointer?

Consider this example, noting that time.Now() returns a time.Time value (not pointer):

package main

import (
    "fmt"
    "time"
)

type foo struct {
    t *time.Time
}

func main() {
    var f foo 

    f.t = time.Now()  // Fail line 15

    f.t = &time.Now() // Fail line 17

    tmp := time.Now() // Workaround
    f.t = &tmp

    fmt.Println(f.t)
}

These both fail:

$ go build
# _/home/jreinhart/tmp/go_ptr_assign
./test.go:15: cannot use time.Now() (type time.Time) as type *time.Time in assignment
./test.go:17: cannot take the address of time.Now()

Is a local variable truly required? And doesn't that incur an unnecessary copy?

Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
  • I believe the local variable is required. So that a space in memory is allocated for time.Now(). f.t is defined as a pointer, but it is nil and doesn't have a place in memory as it wasn't initialized. Then you assign tmp by reference, which tells f.t to become tmp. So you're not copying anything. – reticentroot Feb 27 '17 at 02:25
  • 2
    See possible duplicates for explanation and alternatives: [How do I do a literal *int64 in Go?](http://stackoverflow.com/questions/30716354/how-do-i-do-a-literal-int64-in-go/30716481#30716481); and [How can I store reference to the result of an operation in Go?](http://stackoverflow.com/questions/34197248/how-can-i-store-reference-to-the-result-of-an-operation-in-go/34197367#34197367); and [How to get the pointer of return value from function call?](http://stackoverflow.com/questions/30744965/how-to-get-the-pointer-of-return-value-from-function-call/30751102#30751102) – icza Feb 27 '17 at 08:21
  • Thanks @icza, I definitely spent time searching for this question but I was clearly wording it differently. – Jonathon Reinhart Feb 27 '17 at 10:27

1 Answers1

6

The local variable is required per the specification.

To get the address of a value, the calling function must copy the return value to addressable memory. There is a copy, but it's not extra.

Go programs typically work with time.Time values.

A *time.Time is sometimes used situations where the application wants to distinguish between no value and other time values. Distinguishing between a SQL NULL and a valid time is an example. Because the zero value for a time.Time is so far in the past, it's often practical to use the zero value to represent no value. Use the IsZero() method to test for a zero value.

Charlie Tumahai
  • 113,709
  • 12
  • 249
  • 242
  • Thanks for the note about the idiomatic usage of `time.Time` values (not pointers). The `go-gitlab` API I'm using uses [`*time.Time`](https://github.com/xanzy/go-gitlab/blob/442ae38dfd2f6a1e94d5f384bb6df1784395e732/builds.go#L46) so I thought that was the way to go. – Jonathon Reinhart Mar 03 '17 at 23:43
  • The only reason to have a `*time.Time` is if you want to convey the fact that the time has not been set e.g. reading from a DB where that column can have a `NULL` value. As stated, this leads to cumbersome usage on the client end. So as a compromise, one can use the `IsZero()` method to test if a value is set or not. `go`'s zero-time is `0001-01-01 00:00:00 +0000 UTC` - *NOT* epoch's 1970-01-01 - so that time is unlikely to appear in a DB. – colm.anseo Jun 11 '19 at 14:37