1

I have a struct that consists of a custom time.Time defined for the sake of it having a custom MarshalJSON() interface, following this answer's suggestion:

type MyTime time.Time
func (s myTime) MarshalJSON() ([]byte, error) {
    t := time.Time(s)
    return []byte(t.Format(`"20060102T150405Z"`)), nil
}

I define a MyStruct type with ThisDate and ThatDate fields of type *MyTime:

type MyStruct struct {
    ThisDate *MyTime `json:"thisdate,omitempty"`
    ThatDate *MyTime `json:"thatdate,omitempty"`
}

As far as I understand, I need to use *MyTime and not MyTime so the omitempty tag will have an effect when I'll MarshalJSON a variable of this type, following this answer's suggestion.

I use a library that has a function that returns me a struct with some fields of type *time.Time:

someVar := Lib.GetVar()

I tried to define a variable of type MyStruct like this:

myVar := &MyStruct{
    ThisDate: someVar.ThisDate
    ThatDate: someVar.ThatDate
}

Naturally, it gives me a compilation error:

cannot use someVar.ThisDate (variable of type *time.Time) as *MyTime value in struct literal ...

I tried typecasting someVar.ThisDate with */& and without these without luck. I thought the following would work:

myVar := &MyStruct{
    ThisDate: *MyTime(*someVar.ThisDate)
    ThatDate: *MyTime(*someVar.ThatDate)
}

But it gives me a different compilation error:

invalid operation: cannot indirect MyTime(*someVar.ThisDate) (value of type MyTime) ...

It seems I probably lack basic understanding of pointers and dereferences in Go. Never the less, I would like to avoid finding a specific solution for my issue which comes down to the combination of the need to make omitempty have an effect and a custom MarshalJSON.

8
  • (*MyTime)(someVar.ThisDate) The someVar.ThisDate is already a *time.Time right? so you do not need the * in front of it. Additionally when converting to pointer types, ie *T, I would recommed to always put the pointer type in extra parentheses, ie (*T). play.golang.com/p/jH9Q07sizID Commented May 25, 2019 at 20:03
  • That's very helpful, thank you! Could you perhaps explain further this syntax? I've seen it many times and I don't know even how to search for it in order to find documentation about it. Perhaps even a link to the proper place in tour.golang.org would do. Commented May 25, 2019 at 20:45
  • 2
    golang.org/ref/spec#Conversions If the type starts with the operator * or <-, or if the type starts with the keyword func and has no result list, it must be parenthesized when necessary to avoid ambiguity Commented May 25, 2019 at 20:46
  • 2
    If you understand the concept of operator precedence, or order-of-evaluation, you can see that *T(v) could be interpreted in two ways and is therefore ambiguous, so to avoid the ambiguity you can make your intent clear by adding parentheses (*T)(v). Commented May 25, 2019 at 20:54
  • That's an excellent explanation @mkopriva - exactly what I was missing. Please feel free to put these words into an answer I'll mark as accepted. Commented May 25, 2019 at 21:00

1 Answer 1

6

The problem is the ambiguous syntax of *T(v) or whatever else you tried there. The Golang's spec gives useful examples for type conversions as this, quoting:

*Point(p)        // same as *(Point(p))
(*Point)(p)      // p is converted to *Point

Therefor, since *Point is needed, *T(v) should be used.

Sign up to request clarification or add additional context in comments.

1 Comment

(*T)(v) for a *Point; to get a Point, it's then *(*T)(v).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.