How to get the pointer of return value from function call?

PointersGo

Pointers Problem Overview


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()
}

Pointers Solutions


Solution 1 - Pointers

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 :)

Solution 2 - Pointers

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:

https://stackoverflow.com/questions/30716354/how-do-i-do-a-literal-int64-in-go

Also see related question: https://stackoverflow.com/questions/34197248/how-can-i-store-reference-to-the-result-of-an-operation-in-go/34197367#34197367

Solution 3 - Pointers

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.

Solution 4 - Pointers

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMengView Question on Stackoverflow
Solution 1 - PointershobbsView Answer on Stackoverflow
Solution 2 - PointersiczaView Answer on Stackoverflow
Solution 3 - PointersAleRinaldiView Answer on Stackoverflow
Solution 4 - Pointersuser40176View Answer on Stackoverflow