是什么原因导致ClojureScript中出现“错误:未为类型undefined定义的协议方法XXX.YYY未定义”而不是Clojure?

时间:2018-11-05 06:25:57

标签: clojure clojurescript

我一直收到如下错误:

#object[Error Error: No protocol method XXX.YYY defined for type undefined: ]

其中XXX.YYY部分是可变的。这段代码在* .cljc文件中,可以在JVM Clojure中正常运行,但在ClojureScript中失败。可能是什么原因?

1 个答案:

答案 0 :(得分:1)

此晦涩的错误消息可能是由于对JVM类的无意引用导致的,这些JVM类没有使用#?(:clj ...)#?(:cljs ...)阅读器条件进行适当的保护。对于上面的示例,有问题的代码是这样的:

(ns tupelo.schema
  "Prismatic Schema type definitions"
  (:require [schema.core :as s])
  #?(:clj (:import [java.util HashSet] ))
  #?(:clj (:gen-class)))

(def Set
  "Either a Clojure hash-set or a java.util.HashSet"
  (s/either #{s/Any}
    java.util.HashSet))

正确的版本如下:

(def Set
  "Either a Clojure hash-set or a java.util.HashSet"
  (s/either #{s/Any}
    #?(:clj java.util.HashSet)))   ; <= must guard the java class reference

这些错误特别隐蔽,因为错误消息如此含糊,并且没有引用有问题的文件和行。实际上,在这种情况下,它是由4个文件中的一系列引用引起的:

tst.tupelo.core -> tupelo.core -> tupelo.impl -> tupelo.schema

作为参考,以下是如何成功编写两用CLJ和CLJS代码的示例:

(is (instance?
      #?(:clj  clojure.lang.PersistentVector)
      #?(:cljs    cljs.core/PersistentVector)
      [1 2 3]))

因此,您可以看到CLJ和CLJS中通常都有等效项,但是名称足够不同,因此您必须正确使用阅读器条件#?(:clj ...)#?(:cljs ...)。否则,您的代码将失败,并显示模糊的错误消息。