也许您正在寻找记录?
(require '[clojure.set :as cset])
(defrecord Person [name age address phone email])
;; Make a keyword-based constructor to verify
;; args and decouple ordering.
(let [valid #{:name :age :address :phone :email}]
(defn mk-person[& args]
(let [h (apply hash-map args)
invalid (cset/difference (set (keys h)) valid)]
(when-not (empty? invalid)
(throw (IllegalArgumentException. (pr-str invalid))))
; any other argument validation you want here
(Person.
(:name h) (:age h) (:address h) (:phone h) (:email h)))))
=> (def p (mk-person :name "John" :email "john@hotmail.com"))
#:user.Person{:name "John", :age nil, :address nil, :phone nil,
:email "john@hotmail.com"}
现在您可以通过使用函数(异常)或关键字(非异常)访问数据来选择是否要对错误输入的名称进行异常处理。
=> (.fax p)
java.lang.IllegalArgumentException:
No matching field found: fax for class user.Person
=> (:fax p)
nil
此方法要求您避免与现有方法冲突的字段名称。 (参见@Jouni 的评论。)
或者,您可以通过使用关键字进行查找和检查无效键的访问器函数来绕过字段名称限制:
(defn get-value [k rec]
(let [v (k rec ::not-found)]
(if (= v ::not-found)
(throw (IllegalArgumentException. (pr-str k)))
v)))
=> (get-value :name p)
"John"
=> (get-value :fax p)
IllegalArgumentException: :fax
“解构列表的错误部分”类型的问题可能来自尝试在列表中编码“人”之类的内容;那么您需要记住诸如“邮政编码是 '地址' 列表中的第四个元素在 'person' 列表中的位置 3”之类的东西。
在“经典”Lisp 中,您可以通过编写访问器函数来解决这个问题,在 Clojure 中,您可以使用记录。
错别字会在任何编程语言中引起问题,你能做的最好的就是尽早发现它们。
具有自动补全功能的 Java IDE 可能会在您仍在键入时捕捉到一些拼写错误,而静态类型语言会在编译时捕捉到其中的许多错误,但在动态语言中,您要到运行时才能找到它们。有些人认为这是动态语言(包括 Python、Ruby 等)的缺点,但鉴于它们的流行,不少程序员认为获得的灵活性和节省的代码比失去 IDE 自动完成和编译时错误更重要。
这两种情况的原理都是一样的:早期的异常更好,因为需要通过更少的代码来寻找原因。理想情况下,堆栈跟踪会引导您直接找到错字。在 Clojure 中,记录和访问器函数为您提供了这一点。