Зачем нужен конструктор Go return address?

Я понимаю, что Go не имеет конструкторов, а вместо него используется New func, но согласно этот пример.

func NewFile(fd int, name string) *File {
  if fd < 0 {
    return nil
  }
  f := File{fd, name, nil, 0}
  return &f
}

Они всегда возвращают &f. Почему просто просто вернуть File недостаточно?

Обновление

Я попытался вернуть созданный объект для простой структуры, и это нормально. Поэтому мне интересно, является ли возврат адреса стандартным способом конструктора или что-то в этом роде.

Спасибо.

Ответ 1

Как уже упоминалось, да, спецификация позволяет вам возвращать либо значения (как не указатели), либо указатели. Это просто решение, которое вы должны сделать.

Когда возвращать указатель?

Обычно, если возвращаемое вами значение является "более полезным" в качестве указателя. Когда это более полезно?

Например, если у него есть много методов с приемником указателя. Да, вы можете сохранить возвращаемое значение в переменной, и поэтому оно будет адресуемым, и вы все равно можете вызвать его методы, имеющие приемники указателей. Но если указатель сразу возвращается, вы можете "цеплять" вызовы метода. См. Этот пример:

type My int

func (m *My) Str() string { return strconv.Itoa(int(*m)) }

func createMy(i int) My { return My(i) }

Теперь записываем:

fmt.Println(createMy(12).Str())

приведет к ошибке: cannot call pointer method on createMy(12)

Но если работает, если вы вернете указатель:

func createMy(i int) *My { return (*My)(&i) }

Также, если вы сохраняете возвращаемое значение в структуре данных, которая не адресуется (например, map), вы не можете вызывать методы значений, индексируя карту, потому что значения карты не адресуются.

См. этот пример: My.Str() имеет приемник указателей. Поэтому, если вы попытаетесь сделать это:

m := map[int]My{0: My(12)}
m[0].Str() // Error!

Вы не можете, потому что "не может принимать адрес m[0]". Но следующие работы:

m := map[int]*My{}
my := My(12)
m[0] = &my // Store a pointer in the map

m[0].Str() // You can call it, no need to take the address of m[0]
           // as it is already a pointer

И еще один пример полезности указателей - если это "большая" структура, которая будет передана вокруг много. http.Request - яркий пример. Он большой, он обычно передается многим другим обработчикам, и он имеет методы с приемником указателя.

Если вы вернете указатель, это обычно говорит о том, что возвращаемое значение лучше, если оно хранится и передается как указатель.