web-dev-qa-db-fra.com

Clojure - arguments nommés

Clojure a-t-il des arguments nommés? Si oui, pouvez-vous s'il vous plaît en donner un petit exemple?

75
one-zero-zero-one

Dans Clojure 1.2, vous pouvez déstructurer l'argument rest comme vous le feriez pour déstructurer une carte. Cela signifie que vous pouvez utiliser des arguments de mot clé nommés non positionnels. Voici un exemple:

user> (defn blah [& {:keys [key1 key2 key3]}] (str key1 key2 key3))
#'user/blah
user> (blah :key1 "Hai" :key2 " there" :key3 10)
"Hai there10"
user> (blah :key1 "Hai" :key2 " there")
"Hai there"
user> (defn blah [& {:keys [key1 key2 key3] :as everything}] everything)
#'user/blah
user> (blah :key1 "Hai" :key2 " there")
{:key2 " there", :key1 "Hai"}

N'importe quoi vous pouvez faire la déstructuration d'une carte Clojure dans la liste des arguments d'une fonction, comme indiqué ci-dessus. Y compris using: ou pour définir les valeurs par défaut pour les arguments comme ceci:

user> (defn blah [& {:keys [key1 key2 key3] :or {key3 10}}] (str key1 key2 key3))
#'user/blah
user> (blah :key1 "Hai" :key2 " there")
"Hai there10"

Mais ceci est dans Clojure 1.2. Alternativement, dans les anciennes versions, vous pouvez le faire pour simuler la même chose:

user> (defn blah [& rest] (let [{:keys [key1 key2 key3] :or {key3 10}} (apply hash-map rest)] (str key1 key2 key3)))
#'user/blah
user> (blah :key1 "Hai" :key2 " there")
"Hai there10"

et cela fonctionne généralement de la même manière.

Et vous pouvez également avoir des arguments de position qui viennent avant les arguments de mots clés:

user> (defn blah [x y & {:keys [key1 key2 key3] :or {key3 10}}] (str x y key1 key2 key3))
#'user/blah
user> (blah "x" "Y" :key1 "Hai" :key2 " there")
"xYHai there10"

Celles-ci ne sont pas facultatives et doivent être fournies.

Vous pouvez réellement déstructurer l'argument rest comme n'importe quelle collection Clojure.

user> (defn blah [& [one two & more]] (str one two "and the rest: " more))
#'user/blah
user> (blah 1 2 "ressssssst")
"12and the rest: (\"ressssssst\")"

Vous pouvez faire ce genre de chose même dans Clojure 1.1. La déstructuration de type de carte pour les arguments de mot-clé ne vient que dans 1.2.

114
Rayne

En plus de l'excellente réponse de Raynes, il y a aussi une macro dans clojure-contrib qui facilite la vie:

 user => (utilisez '[clojure.contrib.def: only [defnk]]) 
 nil 
 user => (defnk foo [ab: c 8: d 9] 
 [abcd] ) 
 # 'utilisateur/foo 
 utilisateur => (foo 1 2) 
 [1 2 8 9] 
 utilisateur => (foo 1 2 3) 
 Java.lang.IllegalArgumentException: Aucune valeur fournie pour la clé: 3 (NO_SOURCE_FILE: 0) 
 Utilisateur => (toto 1 2: c 3) 
 [1 2 3 9] 
33
Alex Taggart

Depuis la version 1.8 de Clojure, la prise en charge des mots clés semble encore un peu meh .

Vous pouvez spécifier des arguments de mots clés comme ceci:

(defn myfn1
  "Specifying keyword arguments without default values"
  [& {:keys [arg1 arg2]}]
  (list arg1 arg2))

Exemples d'appeler cela:

(myfn1 :arg1 23 :arg2 45)  --> evaluates to (23 45)
(myfn1 :arg1 22)           --> evaluates to (22 nil)

Si vous souhaitez spécifier des valeurs par défaut pour ces arguments de mots clés:

(defn myfn2
  "Another version, this time with default values specified"
  [& {:keys [arg1 arg2] :or {arg1 45 arg2 55}}]
  (list arg1 arg2))

Ceci fait la chose attendue dans le second cas:

(myfn2 :arg1 22)           --> evaluates to (22 55)

Il existe des avantages et des inconvénients pour chaque partie de chaque langue, mais, à titre de comparaison, procédez comme suit:

(defun myfn3
    (&key arg1 arg2)
    "Look Ma, keyword args!"
    (list arg1 arg2))

(defun myfn4
    (&key (arg1 45) (arg2 55))
    "Once again, with default values"
    (list arg1 arg2))
0
agam

Voulez-vous dire peut-être paramètres nommés? Ceux-ci ne sont pas directement disponibles, mais vous pouvez utiliser cette approche de vecteurs si vous le souhaitez, ce qui peut vous donner ce que vous voulez.

Chez RosettaCode il y a une explication plus profonde sur la façon de procéder en utilisant la déstructuration.

0
Abel