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