10

I have a struct, where one of the fields was declared as String, but it was intended to store a Time. Therefore I changed it to *time.Time (see the commit), note the use of a pointer to bypass the issue where ",omitempty" doesn't really omit the value in case of an blank date.

So far so good. The problem is that now I'm trying to write a code that tests the correct deserialization of the JSON string, but I can't compare the result with

want := Record{Id: 1539, UpdatedAt: time.Date(2014, 01, 15, 22, 03, 04, 0, time.UTC)}

because UpdatedAt is expected to be a pointer *time.Time, whereas time.Date returns a time.Time.

I can't use

want := Record{Id: 1539, UpdatedAt: &time.Date(2014, 01, 15, 22, 03, 04, 0, time.UTC)}

because it is indeed rejected (it expects a pointer, I try to assign a struct)

cannot take the address of time.Date(2014, 1, 15, 22, 3, 3, 0, time.UTC)

Here's my question. Is there a way to create a Record with a time.Date on the fly (hence without assigning the time.Date to a variable and then get the pointer) and/or a workaround for the issue that guarantees I can have a proper nil value assigned when the object is serialized/deserialized and the date is blank?

Community
  • 1
  • 1
Simone Carletti
  • 173,507
  • 49
  • 363
  • 364
  • usually time.Time and time.Date are used without pointers. check the package [time](http://golang.org/pkg/time). All the functions return the struct not the pointer to struct. You should do it too ;) – fabrizioM Jan 16 '15 at 19:33
  • @fabrizioM I explained why the pointer is required. See http://stackoverflow.com/a/22074105/123527 Can you provide an alternative? – Simone Carletti Jan 16 '15 at 20:30

4 Answers4

13

You can't take the address of a function return value because you can only take the address of something that can be assigned to.

Think of it this way: if you store the result in variable, you can then take the address of that variable, but if you don't, then there's nothing you can take the address from.

rvignacio
  • 1,710
  • 1
  • 18
  • 33
  • 1
    Your answer explains the reason, which was already clear to me, but doesn't provide a solution. Can you provide a solution to the issue that guarantees the correct serialization/deserialization of the JSON object with an empty time? – Simone Carletti Jan 16 '15 at 20:33
  • 2
    @SimoneCarletti, there isn't a different solution, you have to do what you wrote in the question: store the value in a variable and then reference that variable. – rvignacio Jan 17 '15 at 23:41
11

You want to store the date value in a variable first and then use the pointer of the variable.

myDate := time.Date(2014, 01, 15, 22, 03, 04, 0, time.UTC)
want := Record{Id: 1539, UpdatedAt: &myDate}
Darren Coxall
  • 1,208
  • 11
  • 11
3

Just for the record, you can define a function like this:

func toTimePtr(t time.Time) *time.Time {
    return &t
}

And then do that:

want := Record{Id: 1539, UpdatedAt: toTimePtr(time.Date(2014, 01, 15, 22, 03, 04, 0, time.UTC))}
Oleg Burov
  • 1,190
  • 11
  • 21
0

You cannot take the address of literals as they get inlined in the code (at least that's my current understanding of the reason).

I often have the following in my test code:

func literalAddressProvider[T any](s T) *T { return &s }

which works for any type (well, all those I have tried so far!). Eg string and time.Time.

You can also use the ToPtr() function of the lo package on github (over 9k stars as I'm writing this post). This works the same, you can write ptr := lo.ToPtr("hello world") (the go compiler is able to infer T as string so no need to specify it, contrary to the many examples that appear in the lo package docs).

Oliver
  • 27,510
  • 9
  • 72
  • 103