2009-07-13 7 views
3

Voici le code:Accès à une carte dans une liste Clojure

(def entry {:name tempName :num tempNum}) 

(def tempList '(entry)) 

(println (get (nth tempList 0) (:name))) 

Exception in thread "main" java.lang.IllegalArgumentException: Wrong number of args passed to keyword: :name 

Dans ce morceau de code, je définis une carte appelée entrée contenant un: nom et un: num, alors je l'ai mis dans une liste , puis j'essaie d'imprimer le champ: name du premier (et seul) élément de la liste. (ou du moins c'est ce que je pense que mon code fait: o)

Je peux accéder au nom de la carte d'entrée avant de le mettre dans la liste, mais une fois dans la liste, je reçois cette erreur. Quels arguments suis-je censé donner?

Répondre

3

Il y a deux problèmes. Tout d'abord, pour les listes qui contiennent des symboles à résoudre (comme l'entrée de symbole dans votre cas), vous devez utiliser syntax-quote (backtick) au lieu de quote normal (apostrophe); si cette ligne:

(def tempList '(entry)) 

devrait être:

(def tempList `(entry)) 

ou tout simplement (en utilisant un vecteur, qui est plus idiomatiques et plus facile à utiliser dans Clojure):

(def tempList [entry]) ; no quoting needed for vectors 

Ensuite, le changement cette ligne

(println (get (nth tempList 0) (:name))) 

à e u bien ce:

(println (get (nth tempList 0) :name)) 

ou ceci:

(println (:name (nth tempList 0))) 
1

prendre la() hors de (: nom) sur la 3ème ligne. : mots-clés sont des fonctions qui prennent une carte comme argument et « se tournent vers » ce qui est très pratique si elle fait l'erreur un peu plus de confusion dans ce cas

 
(get (nth '({:name "asdf"}) 0) :name)) 
2

En utilisant nth sur une liste est une mauvaise idée car il doit faire une recherche linéaire pour récupérer votre élément, à chaque fois. Les vecteurs sont le bon type de collection à utiliser ici.

Les vecteurs sont des "cartes" d'indices à valeurs. Si vous utilisez un vecteur au lieu d'une liste que vous pouvez faire ceci:

(:name (tempList 0)) 

Ou:

(get (get tempList 0) :name) 

Ou:

(get-in tempList [0 :name])) 
1

Je voudrais écrire votre code comme ceci:

(def entry {:name tempName :num tempNum}) 

(def tempList (list entry)) 

(println (:name (first tempList))) 

Notez que first est beaucoup plus propre que d'utiliser nth, et les mots-clés peuvent agir comme des fonctions pour se regarder dans la carte. Une autre approche équivalente consiste à composer les fonctions et à les appliquer à la liste:

((comp println :name first) tempList) 
Questions connexes