1

カスタム文字列表現でレコードを定義する次のマクロを作成しました。

(defmacro defrecord*
  [rname args]
  `(defrecord ~rname [~@args]
     Object
     (toString [_]
       ~(let [kvs (->> args
                       (map (fn [arg] [(str arg ": ") arg]))
                       (interpose ", ")
                       (apply concat))]
          `(str ~rname "(" ~@kvs ")")))))

ただし、toString返されるものは、私が期待しているものとはまったく異なります。

(defrecord* Foo [bar baz]) 
(.toString (Foo. 3 4))

> "class user.Foo(bar: 3, baz: 4)"

この場合toStringは返品したいです。Foo(bar: 3, baz: 4)この形式で文字列表現を取得するには、どのような変更を加える必要がありますか?

また、上記のコードをより慣用的にするために、どのような変更を加える必要がありますか?

4

2 に答える 2

4

- に置き換えるだけ~rnameで、現在のスコープ内の値ではなく'~rname、実際のシンボルが必要です。これは classです。Foouser.Foo

また、間違った順序で(apply concat)andを持っています - シーケンスとして扱い、単一の文字列の代わりに文字と文字を追加します。それを交換すると、代わりに が必要であることが明らかになります。したがって、let ブロック全体を次のようなものに置き換えます。(interpose ", ")", "\,\spacemapcat(apply concat (map ...))

`(str '~rname
      "(" ~@(interpose ", "
                       (mapcat (fn [arg] [(str arg ": ") arg])
                               args))
      ")")

または、本当にパフォーマンスを向上させたい場合~(str "(" rname)は、実行時ではなくコンパイル時に計算できます。

ただし、Clojure 1.3 の時点で、レコードは既にこれと非常によく似た方法で出力されることに注意してください。したがって、デバッグを簡単にするためにこれを行っているだけであれば、気にしないでください。の出力を後で使用しているためにそれを行っている場合...まあ、主にデバッグ用であるため.toString、そのコードを書いた人は残念です。.toString

于 2012-07-10T07:01:16.093 に答える
2

に変更~rnameするだけ~(name rname)です:

(defmacro defrecord*
  [rname args]
  `(defrecord ~rname [~@args]
     Object
     (toString [_]
       ~(let [kvs (->> args
                       (map (fn [arg] [(str arg ": ") arg]))
                       (interpose ", ")
                       (apply concat))]
          `(str ~(name rname) "(" ~@kvs ")")))))
于 2012-07-10T06:58:21.257 に答える