Для меня очень непонятно, в каком случае я хотел бы использовать приемник значения вместо того, чтобы всегда использовать приемник указателя.
Резюмируя из документов:
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 нс / операцию)
Может ли кто-нибудь сказать мне случай, когда приемник значения явно имеет больше смысла, чем приемник указателя? Или я что-то не так делаю в тесте, не учел другие факторы?