73

I just need a pointer to time.Time, so the code below seems invalid:

./c.go:5: cannot take the address of time.Now()

I just wonder why? Is there any way to do that except to do assignment to a variable first and take the pointer of the variable?

package main

import "time"
func main() {
    _ = &time.Now()
}

4 Answers 4

84

The probably unsatisfying answer is "you can't do it because the spec says so." The spec says that to use & on something it has to be addressable or a compound literal, and to be addressable it has to be "a variable, pointer indirection, or slice indexing operation; or a a field selector of an addressable struct operand; or an array indexing operation of an addressable array." Function calls and method calls are definitely not on the list.

Practically speaking, it's probably because the return value of a function may not have a usable address; it may be in a register (in which case it's definitely not addressable) or on the stack (in which case it has an address, but one that won't be valid if it's put in a pointer that escapes the current scope. To guarantee addressability, Go would have to do pretty much the exact equivalent of assigning it to a variable. But Go is the kind of language that figures that if it's going to allocate storage for a variable it's going to be because you said to, not because the compiler magically decided to. So it doesn't make the result of a function addressable.

Or I could be over-thinking it and they simply didn't want to have a special case for functions that return one value versus functions that return multiple :)

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

2 Comments

But compiler could figure out that you are doing &time.Now() and make sure that it is assigned to a variable for you.
@Mitar already mentioned in my answer.
46

You can't directly take the address of a function call (or more precisely the return value(s) of the function) as described by hobbs.

There is another way but it is ugly:

p := &[]time.Time{time.Now()}[0]
fmt.Printf("%T %p\n%v", p, p, *p)

Output (Go Playground):

*time.Time 0x10438180
2009-11-10 23:00:00 +0000 UTC

What happens here is a struct is created with a literal, containing one element (the return value of time.Now()), the slice is indexed (0th element) and the address of the 0th element is taken.

So rather just use a local variable:

t := time.Now()
p := &t

Or a helper function:

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

p := ptr(time.Now())

Which can also be a one-liner anonymous function:

p := func() *time.Time { t := time.Now(); return &t }()

Or as an alternative:

p := func(t time.Time) *time.Time { return &t }(time.Now())

For even more alternatives, see:

How do I do a literal *int64 in Go?

Also see related question: How can I store reference to the result of an operation in Go?

1 Comment

To add to this, since Go 1.18 has generics: ``` func ptr[T any](obj T) *T { return &obj } ```
11

Fortunately, generics now offer quite a clean solution by defining a function only one time, that can be used on any type:

package main

func ptr[T any](x T) *T {
    return &x
}

func main() {
    print(ptr("foo"))
    print(ptr(42))
}

Playground: https://go.dev/play/p/TgpEPKjpXX7

However, this will work only starting from Golang 1.18. For previous versions, you'll need a function for each type, as other answers suggested.

Comments

-1

If you are having this trouble with a function you wrote, change your function to return a pointer. Even though you can't take the address of a return value, you can dereference a return value, so it will be suitable whether you want the pointer or the object.

func Add(x, y int) *int {
    tmp := x + y
    return &tmp
}

func main() {
    fmt.Println("I want the pointer: ", Add(3, 4))
    fmt.Println("I want the object: ", *Add(3, 4))
}

https://play.golang.org/p/RogRZDNGdmY

1 Comment

The answer doesn't seem to be relevant to the OP's question as the example mentions time.Time() - which you can't modify.

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.