Clojure: 如何在 Java 类上使用 Case Switch

3
我有一个Clojure里的Java类,它来自于一个返回类的方法。我想要对它们进行case switch,像这样:
            (case type
                java.lang.String (println "Found String" name)
                java.lang.Long (println "Found Long" name)
                java.nio.ByteBuffer (println "Found ByteBuffer" name)
                java.lang.Boolean (println "Found Boolean" name)
                java.math.BigDecimal (println "Found BigDecimal" name)
                java.lang.Double (println "Found Double" name)
                java.lang.Float (println "Found Float" name)
                java.net.InetAddress (println "Found InetAddress" name)
                java.lang.Integer (println "Found Integer" name)
                java.util.Date (println "Found Date" name)
                java.util.UUID (println "Found UUID" name)
                java.math.BigInteger (println "Found BigInteger" name)
                java.util.List (println "Found List" name)
                java.util.Set (println "Found Set" name)
                java.util.Map (println "Found Map" name))

但是当我运行这个时,出现了以下情况:
 java.lang.IllegalArgumentException: No matching clause: class java.util.UUID

当找不到匹配的情况时,会抛出什么。如何在case子句中匹配类?


好的,知道这个不应该工作。但也许它藏在答案中,为什么它不能按预期工作呢? - matanster
4个回答

5
你不能比cheshire更好地完成这项任务,它基本上是通过重复调用instance?来实现的,就像这样:
(condp instance? x
  String :string
  Integer :int
  :unknown)

如果您不想关注子类型,只想使用对x的类型进行精确匹配,可以使用(condp = (class x) ...)代替。

3
使用地图而不是case表单:
def case-map
  {java.util.Set "Set",
   java.math.BigInteger "BigInteger",
   java.lang.Double "Double",
   java.math.BigDecimal "BigDecimal",
   java.util.List "List",
   java.lang.Float "Float",
   java.util.UUID "UUID",
   java.lang.String "String",
   java.lang.Integer "Integer",
   java.nio.ByteBuffer "ByteBuffer",
   java.lang.Boolean "Boolean",
   java.net.InetAddress "InetAddress",
   java.util.Date "Date",
   java.util.Map "Map",
   java.lang.Long "Long"})

(defn what-is [x] (str (case-map (type x)) " " x))

例如:

(what-is (java.util.Date.))
"Date Mon Sep 22 08:17:55 BST 2014"

(what-is (java.util.UUID. 0 0))
"UUID 00000000-0000-0000-0000-000000000000"

编辑:@cgrand's answer 中提到的有关AOT编译的警告似乎也适用于这个解决方案。


如果你在函数内部构建map而不是在外部,就可以避免AOT编译问题。当然,这样做你将不断付出构建的代价。 - amalloy
1
哇,我真的建议一遍又一遍地构建这张地图吗?更好的解决AOT的方法是定义一个地图的延迟,而不是地图本身,这样它会在第一次使用时构建,而不是在编译时或一遍又一遍地构建:(def case-map (delay {...})) (defn what-is [x] (get @case-map (class x))) - amalloy

1
这是如何绕过这个问题的方法:
=> (map #(case (class %)
           #=java.lang.String (str "Found String " %)
           #=java.lang.Long (str "Found Long " %))
     ["a" 42])
("Found String a" "Found Long 42")

然而,由于类没有稳定的哈希码,因此不要在AOT编译的代码中使用它。


这篇帖子质疑了两三年前#= ...的状态。而且现在仍未被记录。使用它是否安全? - Thumbnail
@缩略图编号。不要使用它。 - amalloy

0

我最终使用了多方法

(defmulti get-row-data-for-class (fn [type-class name row] type-class))
(defmethod get-row-data-for-class java.lang.Boolean [type-class name row] (.getBool row name))
(defmethod get-row-data-for-class java.lang.Double [type-class name row] (.getDouble row name))
(defmethod get-row-data-for-class java.lang.Float [type-class name row] (.getFloat row name))

然后类似于

(let [data (get-row-data-for-class type-class name row)])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接