пятница, 15 февраля 2019 г.

Go FAQ: Следует ли определять методы для значений или указателей?

// метод для указателя
func (s *MyStruct) pointerMethod() { } 

// метод для значения
func (s MyStruct)  valueMethod()   { } 

Для программистов, не привыкших к указателям, различие между этими двумя примерами может сбивать с толку, но на самом деле ситуация очень проста. При определении метода для типа получатель (s в приведенных выше примерах) ведет себя точно так же, как если бы это был аргумент метода. Определять ли получатель как значение или как указатель - это тот же вопрос что и, должен ли аргумент функции быть значением или указателем? Есть несколько соображений по этому поводу.

Во-первых, и это наиболее важно, метод должен изменить получатель? Если это так, получатель должен быть указателем. (Срезы и карты выступают в качестве ссылок, поэтому их история немного более тонкая, но, например, для изменения длины среза в методе получатель должен быть указателем.) В приведенных выше примерах, если pointerMethod изменяет поля s, вызывающая сторона увидит эти изменения, но valueMethod вызывается с копией аргумента вызывающей стороны (это определение передачи значения), поэтому изменения, которые он вносит, будут невидимы для вызывающей стороны.

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

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

Следующее - последовательность. Если некоторые из методов типа должны иметь приемник указателя, остальные тоже должны, поэтому набор методов соответствует независимо от того, как используется тип.

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


Читайте также:


Комментариев нет:

Отправить комментарий