Подтвердить что ты не робот

Как получить указатель возвращаемого значения из вызова функции?

Мне просто нужен указатель на time.Time, поэтому код ниже кажется недействительным:

./c.go: 5: не может принимать адрес времени. Теперь()

Я просто удивляюсь, почему? Есть ли способ сделать это, кроме как выполнить назначение переменной сначала и взять указатель на переменную?

package main

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

Ответ 1

Вероятно, неудовлетворительный ответ: "вы не можете этого сделать, потому что спецификация говорит так". Спектр говорит, что для использования & для чего-то это должно быть addressable или составной литерал, и чтобы быть адресуемым, оно должно быть "переменная, указатель указателя или операция индексации среза или полевой селектор адресного управляющего операнда или операция индексирования массива адресного массива". Функциональные вызовы и вызовы методов, безусловно, не входят в список.

Практически говоря, это, вероятно, потому, что возвращаемое значение функции может не иметь полезного адреса; он может быть в регистре (в этом случае он определенно не адресуется) или в стеке (в этом случае он имеет адрес, но тот, который не будет действителен, если он поместит указатель, который выходит из текущей области. адресности, Go должен был бы сделать в значительной степени точный эквивалент присвоения ему переменной. Но Go - это тип языка, который показывает, что если он собирается распределить память для переменной, это будет потому, что вы сказали, а не потому, что компилятор волшебно решил, поэтому он не делает результат функции адресуемой.

Или я мог бы передумать, и они просто не хотели иметь специальный случай для функций, которые возвращают одно значение по сравнению с функциями, которые возвращают несколько:)

Ответ 2

Вы не можете напрямую получить адрес вызова функции (или, точнее, возвращаемого значения (ей) функции), как описано в hobbs.

Есть и другой путь, но он безобразен

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

Выход (Go Playground):

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

Здесь происходит создание struct с литералом, содержащим один элемент (возвращаемое значение time.Now()), фрагмент индексируется (0- й элемент) и берется адрес 0- го элемента.

Так что лучше просто использовать локальную переменную:

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

Или вспомогательная функция:

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

p := ptr(time.Now())

Который также может быть однострочной анонимной функцией:

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

Или как альтернатива:

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

Еще больше альтернатив см.:

Как мне сделать литерал * int64 в Go?

Также см. Связанный вопрос: Как я могу сохранить ссылку на результат операции в Go?