Для меня очень непонятно, в каком случае я хотел бы использовать приемник значения вместо того, чтобы всегда использовать приемник указателя.
Резюмируя из документов:
type T struct {
a int
}
func (tv T) Mv(a int) int { return 0 } // value receiver
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
В документации также говорится: «Для таких типов, как базовые типы, срезы и небольшие структуры, приемник значения очень дешев, поэтому, если семантика метода не требует указателя, приемник значения эффективен и понятен».
Во-первых, он «очень дешевый», но вопрос в том, что он дешевле, чем указательный приемник. Поэтому я сделал небольшой тест (код по сути), который показал мне, что этот приемник указателя работает быстрее даже для структуры, имеющей только одно строковое поле. Вот результаты:
// Struct one empty string property
BenchmarkChangePointerReceiver 2000000000 0.36 ns/op
BenchmarkChangeItValueReceiver 500000000 3.62 ns/op
// Struct one zero int property
BenchmarkChangePointerReceiver 2000000000 0.36 ns/op
BenchmarkChangeItValueReceiver 2000000000 0.36 ns/op
(Изменить: обратите внимание, что второй пункт стал недействительным в более новых версиях go, см. Комментарии) .
Во-вторых, он говорит, что это «эффективно и ясно», что больше вопрос вкуса, не так ли? Лично я предпочитаю последовательность, используя везде одинаково. Эффективность в каком смысле? с точки зрения производительности кажется, что указатель почти всегда более эффективен. Несколько тестовых прогонов с одним свойством int показали минимальное преимущество приемника Value (диапазон 0,01-0,1 нс / операцию)
Может ли кто-нибудь сказать мне случай, когда приемник значения явно имеет больше смысла, чем приемник указателя? Или я что-то не так делаю в тесте, не учел другие факторы?
Ответы:
Обратите внимание, что в FAQ упоминается согласованность
Как упоминалось в этой теме :
Сейчас:
Комментарий Код Обзор может помочь:
Часть, выделенная жирным шрифтом, находится, например, в
net/http/server.go#Write()
:источник
The rule about pointers vs. values for receivers is that value methods can be invoked on pointers and values, but pointer methods can only be invoked on pointers
На самом деле неправда. Методы приемника значения и приемника указателя могут быть вызваны для правильно набранного указателя или не указателя. Независимо от того, для чего вызывается метод, в теле метода идентификатор получателя ссылается на значение копии, когда используется получатель значения, и указатель, когда используется получатель указателя: см. Play.golang.org/p / 3WHGaAbURMInt(5).increment_by_one_ptr()
. Точно так же признак, определяющий методincrement_by_one_ptr
, не будет удовлетворен значением типаInt
.Чтобы добавить в @VonC отличный информативный ответ.
Я удивлен, что никто на самом деле не упомянул стоимость обслуживания, когда проект разрастется, старые разработчики уйдут и появятся новые. Го, безусловно, молодой язык.
Вообще говоря, я стараюсь избегать указателей, когда могу, но они имеют свое место и красоту.
Я использую указатели, когда:
Например:
Причины, по которым я избегаю указателей:
Мое эмпирическое правило - напишите как можно больше инкапсулированных методов, например:
ОБНОВИТЬ:
Этот вопрос вдохновил меня на дальнейшее изучение темы и написать об этом сообщение в блоге https://medium.com/gophersland/gopher-vs-object-oriated-golang-4fa62b88c701
источник