2012-02-18 10 views
8

は、このようなマップのいくつかのキーをdestructureすることが可能である:Clojureでは、マップのすべてのキーをどのように破壊するのですか? Clojureので

(let [{:keys [cpp js]} {:cpp 88 :js 90}] 
    (println js); 90 
    (println cpp); 88 
) 

は、マップのすべてキーをdestructureする方法はありますか?

たぶんのようなもの:本当に

(let [{:all-the-keys} {:cpp 88 :js 90}] 
    (println js); 90 
    (println cpp); 88 
) 

答えて

22

ない、それは良い考えではないでしょう。想像してみてください:

(let [{:all-the-keys} m] 
    (foo bar)) 

fooとbarグローバルはありますか?地方自治体?あなたはmから抽出すべきキーですか? m 時にはにfooキーが含まれていて、fooもグローバル関数である場合、このコードは何を行うべきですか?ときにはグローバル関数を呼び出すこともありますが、mに格納されている関数を呼び出すこともあります。

技術的な問題(そのほとんどはおそらく克服することができます)を無視すると、読みやすさと予測可能性にとっては本当に災難です。どのキーを抜きたいのかを明示してください。頻繁に同じテンキーを抜きたい場合は、普通のケースを簡略化する(with-person p body)のような単純なマクロを書くことができます。

6

あなたは(事実上のミニDSLを作成する)これを行うには、マクロを書くことができますが、私はそれは次の理由のために非常に良いアイデアだとは思わない:右を作成するためには

  • コンパイル時のリテラルjsとcppをコンパイルするときは、コンパイル時にマップの構造を解除する必要があります。これはあなたが何をすることができるかという点でかなり制限されています(例えば、キーをあらかじめ指定しなければならず、高次関数では使用できません)。
  • マクロは、私はちょうどマップ上のループにあなたのケースでは、単純なdoseqを使用してお勧めします簡単な方法の仕事をするでしょう(下記参照)

(let [my-map {:cpp 88 :js 90}] 
    (doseq [[k v] my-map] 
    (println v))) 

なお:

  • あなたは
  • は、非怠惰なので、私は doseqではなく forを使用し、それはあなただけのためにループを使用していることを、この例では思わ
  • 各マップエントリからキーkと値vの両方を抽出するために、上記のような破壊を使用することができますprintln副作用。
  • 代わりに値の怠惰なシーケンス(88 90)が必要な場合は、forが適切です。
7

この質問はかなり古いですので、おそらく忘れてしまったかもしれませんが、同じことをやろうとしていたときにGoogleに出てきました。

(defmacro let-map [vars & forms] 
    `(eval (list 'let (->> ~vars keys 
         (map (fn [sym#] [(-> sym# name symbol) (~vars sym#)])) 
         (apply concat) vec) 
       '~(conj forms 'do)))) 

は、これは基本的に、その後結合形[cpp 88 js 90]にマップ{:cpp 88 :js 90}を変換し、これは実行時に起こることを確認するためにいくつかのeval-実印を実行するとともに、結合letを構築します。

(def test-map {:cpp 88 :js 90}) 
(let-map test-map 
    (println js) 
    (println cpp)) 
;=> 90 
;=> 88 
+1

Oh、cmon、これは実際にタイトルの質問に答える唯一の答えです。ありがとう。 – desudesudesu

+1

これは非常に巧妙なマクロです。その創意工夫を認識し、生産コードのようなものを書くことは絶対にしないようにしましょう。 – MichaelBlume

+0

ベストプラクティスのようには見えないかもしれませんが、私はこの構築に有効なユースケースがあると主張しています。 –

関連する問題