web-dev-qa-db-ja.com

clojureのどこでdefrecordを使用すればよいですか?

Clojureプログラムでは、多くのマップと構造体を使用しています。これらをdefrecordに変換することの利点(パフォーマンスを除く)は何ですか?

71
Yazz.com

構造体は効果的に非推奨になっているので、まったく使用しません。

多くのマップインスタンスで使用される既知のキーの固定セットがある場合、通常はレコードを作成します。大きなメリットは次のとおりです。

  • パフォーマンス
  • 生成されたクラスには、マルチメソッドまたは他の状況でオンにできるタイプがあります
  • Defrecordに関連する追加のマクロ機構を使用して、フィールドの検証、デフォルト値、およびその他の必要なものを取得できます
  • レコードは任意のインターフェースまたはプロトコルを実装できます(マップは実装できません)
  • レコードはほとんどの目的でマップとして機能します
  • キーと値は、安定した(作成ごとの)順序で結果を返します

レコードのいくつかの欠点:

  • レコードはJavaクラスインスタンス(Clojureマップではない))であるため、構造的な共有は行われないため、同じレコード構造は、変更された同等のマップ構造よりも多くのメモリを使用する可能性があります。レコードを「変更」したときのオブジェクトの作成/破棄。JVMは、この種の短命なゴミを汗をかくことなく食べるように特別に設計されています。
  • 開発中にレコードを変更する場合は、おそらくREPLをより頻繁に再起動して、それらの変更を反映する必要があります。これは通常、開発の狭い段階でのみ問題になります。
  • 既存のライブラリの多くは、レコードをサポートするように更新されていません(ポストウォーク、Zip、マッチなど)。必要に応じてこのサポートを追加しました。
88
Alex Miller

Stuart Sierraは最近、「Clojure 1.2による式の問題の解決」に関する興味深い記事を書きました。これには、defrecordに関するセクションも含まれています。

http://www.ibm.com/developerworks/Java/library/j-clojure-protocols/index.html#datatypes

記事全体がプロトコルと記録を理解するための良い出発点だと思います。

14
Michael Kohl

もう1つの主な利点は、レコードに、ディスパッチできる型(そのクラス)があることです。

この機能を使用するが、すべての可能な使用法の代表ではない例は次のとおりです。

(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"
9
bmillare

ほとんどの場合にマップを使用し、多態性が必要な場合にのみ記録します。マップだけでもマルチメソッドを使用できます。ただし、プロトコルが必要な場合は、レコードが必要です。これを前提として、レコードに頼る前にプロトコルが必要になるまで待ちます。それまでは、データ中心でより単純なコードを優先して、それらを避けてください。

2
Mario

前述の内容に加えて、一般的にパフォーマンスの面で同等または優れていることに加えて、同じプログラミングインターフェイスをマップとして公開する場合、レコードは穏やかな構造を適用します。キー名とキーの数は、定義。これは、同じ構造が多くの値から予期される(または、それ以外の場合は人工的に固定されている)愚かなエラーを回避するのに役立ちます。

元の動機が何であれ、このプロパティもマップとは一線を画しています。

0
matanster