如何在Clojure的case语句中匹配defrecord类型?为何匹配失败
为什么使用记录类型时
case语句无法正常工作? 这是Clojure的case宏的两个特性共同导致的:
case的分支匹配值是编译期固定的字面量,不会在运行时对分支位置的符号做求值解析:你在分支位置写的Thing不会被解析为defrecord生成的类对象,只会被当作'Thing这个符号值参与匹配,而(type x)返回的是类对象,二者类型完全不同,自然匹配失败。case的匹配逻辑使用的是严格对象相等判断identical?,而非你测试时用的通用值相等判断=,即使值相等但不是同一个对象也无法匹配(本问题的核心诱因是第一条)。
你直接执行(= (type (Thing. 123)) Thing)能返回true,是因为普通表达式中的Thing会被正常求值为对应记录的类对象,和type的返回值一致。
解决方案
方案1:使用condp替代
condp会在运行时对分支值做求值,且默认使用=做匹配,符合你的预期:
(defn foo [x] (condp = (type x) Thing "Thing found!" "nope!")) (foo (Thing. 123)) ;; => "Thing found!"
方案2:使用cond + instance?(更推荐的类型检查写法)
对于类型校验场景,直接用instance?判断实例所属类型更符合Clojure的惯用写法,不需要手动获取type比较:
(defn foo [x] (cond (instance? Thing x) "Thing found!" :else "nope!"))
方案3:非要用case的处理方式
如果必须使用case,需要保证分支值是编译期可确定的类字面量,写全限定类名即可:
(defn foo [x] (case (type x) myproject.core.Thing "Thing found!" "nope!"))
内容的提问来源于stack exchange,提问作者I was in the neighborhood
相关产品推荐
相关产品推荐

