Что вызывает «Ошибка: в ClojureScript не определен метод протокола XXX.YYY для типа undefined», но не Clojure? - PullRequest
0 голосов
/ 05 ноября 2018

Я получаю ошибки, подобные следующим:

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

где часть XXX.YYY является переменной. Этот код находится в файле * .cljc и отлично работает в JVM Clojure, но не работает в ClojureScript. В чем может быть причина?

1 Ответ

0 голосов
/ 05 ноября 2018

Это неясное сообщение об ошибке может быть вызвано непреднамеренными ссылками на классы 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 ...). В противном случае ваш код потерпит неудачу с неопределенным сообщением об ошибке.

...