Я использую много карт и структур в моих программах clojure. Каковы преимущества (помимо производительности) их преобразования в дефрагментацию?
Где я должен использовать defrecord в clojure?
Ответ 1
Я считаю, что структуры эффективно устарели, поэтому я их вообще не использую.
Когда у меня есть фиксированный набор хорошо известных ключей, используемых во многих экземплярах карты, я обычно создаю запись. Большие преимущества:
- Производительность
- Сгенерированный класс имеет тип, который я могу включить в разных методах или в других ситуациях.
- С дополнительными макромашинами вокруг defrecord я могу получить проверку поля, значения по умолчанию и любые другие вещи, которые я хочу.
- Записи могут реализовывать произвольные интерфейсы или протоколы (карты не могут)
- Записи выступают в качестве карт для большинства целей.
- и vals возвращают результаты в стабильном (за создание) порядке
Некоторые недостатки записей:
- Поскольку записи представляют собой экземпляры Java-класса (а не Clojure maps), структурный обмен отсутствует, поэтому одна и та же структура записей, скорее всего, будет использовать больше памяти, чем эквивалентная структура карты, которая была изменена. Существует также больше создания/уничтожения объектов, поскольку вы "меняете" запись, хотя JVM спроектирован специально, чтобы съесть этот вид короткоживущего мусора, не разбивая пота.
- Если вы меняете записи во время разработки, вам, вероятно, придется чаще перезапускать REPL, чтобы получить эти изменения. Обычно это проблема только при узких битах разработки.
- Многие существующие библиотеки не были обновлены для поддержки записей (postwalk, zip, matchure и т.д. и т.д.). Мы добавили эту поддержку по мере необходимости.
Ответ 2
Стюарт Сьерра недавно написал интересную статью "Решение проблемы выражения с Clojure 1.2", которая также содержит раздел на defrecord
:
http://www.ibm.com/developerworks/java/library/j-clojure-protocols/index.html#datatypes
Я думаю, что вся статья является хорошей отправной точкой для понимания протоколов и записей.
Ответ 3
Другим важным преимуществом является то, что запись имеет тип (класс), от которого вы можете отправить.
Пример, который использует эту функцию, но не является репрезентативным для всех возможных применений, заключается в следующем:
(defprotocol communicate
(verbalize [this]))
(defrecord Cat [hunger-level]
communicate
(verbalize [this]
(apply str (interpose " " (repeat hunger-level "meow")))))
(defrecord Dog [mood]
communicate
(verbalize [this]
(case mood
:happy "woof"
"arf")))
(verbalize (->Cat 3))
; => "meow meow meow"
(verbalize (->Dog :happy))
; => "woof"
Ответ 4
Использовать карты в большинстве случаев и записывать только тогда, когда требуется полиморфизм. Только с картами вы все равно можете использовать мультиметоды; однако вам нужны записи, если вы хотите протоколы. Учитывая это, подождите, пока вам не понадобятся протоколы, прежде чем прибегать к записи. До тех пор, избегайте их в пользу более ориентированного на данные и более простого кода.
Ответ 5
В дополнение к тому, что было ранее отмечено, помимо того, что он обычно находится на уровне или превосходит по производительности, а также при экспонировании того же программного интерфейса, что и карта, записи обеспечивают мягкую структуру: имена ключей и количество ключей принудительно применяются в время определения. Это может быть полезно для избежания глупых ошибок, когда ожидается, что одна и та же структура ожидается из многих значений (или просто искусственно жесткой в противном случае).
Какими бы ни были оригинальные мотивы, это свойство также отличает его от карт.