Scala toString: заключить в скобки или нет? - PullRequest
21 голосов
/ 14 ноября 2011

Мне бы хотелось, чтобы эта ветка представляла собой краткое изложение плюсов / минусов для переопределения и вызова toString с пустыми скобками или без них, потому что эта штука иногда все еще смущает меня, даже несмотря на то, что я был в Scala довольнокакое-то время.

Так какой из них предпочтительнее другого?Высоко ценятся комментарии фанатов Scala, официальных лиц и параноиков ОКР.

Плюсы к toString:

  • на первый взгляд кажется очевидным и естественным выбором;
  • большинство случаев тривиальны и просто строят строки на лету, не изменяя внутреннее состояние;
  • другой распространенный случай - делегирование вызова метода в обернутой абстракции:

    override def toString = underlying.toString
    

Достоинства до toString():

  • определенно не «похожее на имя» (именно так инспектор IntelliJ IDEA жалуется время от времени);
  • может подразумевать некоторую работу процессора или ввода-вывода (в тех случаях, когда подсчет каждого вызова System.arrayCopy имеет решающее значение для производительности);
  • даже может означать изменение изменяемого состояния (рассмотрим пример, когда первый вызов toString стоит дорогопоэтому он кешируется внутри, чтобы в будущем вызывать более быстрые вызовы.)

Так что же является лучшей практикой?Я все еще что-то упускаю?

Обновление : этот вопрос относится конкретно к toString, который определен для каждого объекта JVM, поэтому я надеялся найти лучший метод , если он вообще существует.

Ответы [ 4 ]

22 голосов
/ 14 ноября 2011

Вот что Программирование в Scala (раздел 10.3) должно сказать:

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

Вот что (неофициально) ScalaРуководство по стилю (стр. 18) должно сказать:

Scala позволяет пропускать скобки для методов arity-0 (без аргументов):

reply() 
// is the same as 
reply 

Однако этот синтаксис следует использовать только в том случае, если рассматриваемый метод не имеет побочных эффектов (чисто функциональный).Другими словами, было бы приемлемо опустить круглые скобки при вызове queue.size, но не при вызове println ().Это соглашение отражает соглашение об объявлении метода, приведенное выше.

В последнем не упоминается принцип унифицированного доступа.

Если ваш метод toString может быть реализован как val, это означает, что поле является неизменным.Однако, если ваш класс изменчив, toString может не всегда давать один и тот же результат (например, для StringBuffer).Итак, Программирование в Scala подразумевает, что мы должны использовать toString() в двух различных ситуациях:

1) Когда его значение является изменяемым

2)Когда есть побочные эффекты

Лично я думаю, что более распространенным и более последовательным является игнорирование первого из них.На практике toString почти никогда не будет иметь побочных эффектов.Поэтому (если это не так) всегда используйте toString и игнорируйте принцип унифицированного доступа (следуя Руководство по стилю ): сохраняйте скобки для обозначения побочных эффектов, а не изменчивости.

9 голосов
/ 14 ноября 2011

Да, вы что-то упускаете: семантика.

Если у вас есть метод, который просто возвращает значение, вы не должны использовать парены. Причина в том, что это стирает грань между val с и def с, удовлетворяя принципу Uniform Access Например. рассмотрим метод size для коллекций. Для векторов или массивов фиксированного размера это может быть просто val, другие коллекции могут потребовать его вычисления.

Использование пустых паренов должно быть ограничено методами, которые выполняют какой-либо побочный эффект, например, println(), или метод, который увеличивает внутренний счетчик, или метод, который сбрасывает соединение и т. Д.

3 голосов
/ 15 ноября 2011

Я бы порекомендовал всегда использовать toString.Относительно вашего третьего «профи» до toString():

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

Прежде всего, toString обычно не должен быть дорогой операцией.Но предположим, что это дорого, и предположим, что вы решили кэшировать результат внутри.Даже в этом случае я бы сказал, использовать toString, пока результат из toString всегда одинаков для данного состояния объекта (не учитывая состояние кэша toString).

Единственная причина, по которой я бы не рекомендовал использовать toString без паренов, - это если у вас есть профилировщик / анализатор кода, который делает предположения на основании наличия или отсутствия паренов.В этом случае следуйте соглашениям, изложенным указанным профилировщиком.Кроме того, если ваш toString такой сложный, попробуйте переименовать его во что-нибудь еще, например expensiveToString.Неофициально ожидается, что toString будет простой, простой функцией в большинстве случаев.

2 голосов
/ 15 ноября 2011

В этом ответе не так много аргументов, но только GenTraversableOnce объявляет следующие определения без скобок:

toArray
toBuffer
toIndexedSeq
toIterable
toIterator
toList
toMap
toSeq
toSet
toStream
toTraversable
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...