#clojure #clojure-java-interop
#clojure #clojure-java-взаимодействие
Вопрос:
Следующий пример функции, которая использует специальную форму Clojure для взаимодействия с Java для вызова конструктора класса, вызывает предупреждение об отражении:
(defn test-reflection-err []
(new java.util.HashMap {}))
Это сообщение гласит:
Reflection warning, /Users/ethan/Projects/scicloj/tablecloth.time/src/tablecloth/time/index.clj:26:3 - call to java.util.HashMap ctor can't be resolved.
Я пробовал размещать подсказки типа, чтобы избежать этого, но не уверен, где их разместить, чтобы предотвратить ошибку отражения. Кто-нибудь знает, как это сделать?
Я пробовал:
(defn test-reflection-err []
(^TreeMap new java.util.HashMap {}))
и
(defn test-reflection-err []
(doto ^TreeMap (new java.util.HashMap {})))
Ответ №1:
Вам нужно добавить подсказку к аргументу конструктора:
(let [^java.util.Map m {}]
(new java.util.HashMap m))
Комментарии:
1. Я делаю что-то не так? Я все еще получаю предупреждение об отражении с помощью этой техники. Это удается, с подсказкой типа или без нее.
2. @AlanThompson — я не уверен, что
spyxx
делает, но для меня в clojure 1.10.1 REPL, если я делаю(set! *warn-on-reflection* true)
, тогда(new java.util.HashMap {})
появляется предупреждение об отражении, а(let [^java.util.Map m {}] (new java.util.HashMap m))
не нет. Я думаю, что ваш подсказка типа дляm2
находится, по крайней мере, не в том месте, и так и должно быть(def ^java.util.Map m2 {})
3. Я добавил некоторые обновления к другому ответу, чтобы прояснить неожиданное поведение, которое я наблюдал.
4. @Lee интересно, можете ли вы объяснить, может быть, даже добавить к ответу, почему это работает. Одна вещь, которая меня смущает, это то, что предупреждение о отражении говорит, что это вызов ctor HashMap, который он не может разрешить. Тем не менее, мы исправляем это, добавляя подсказку типа к аргументу Map, который передается в ctor HashMap. Было бы здорово, если бы вы могли внести больше ясности в то, что происходит — если позволяет время, конечно ;).
Ответ №2:
Если вам действительно не нужно по какой-то причине исключить все отражения, самый простой ответ — поместить эту строку в свой project.clj
:
:global-vars {*warn-on-reflection* false}
Я не смог получить подсказку типа, чтобы устранить предупреждение при использовании пустой карты Clojure в качестве аргумента конструктора. Соблюдайте этот код:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(dotest
(newline)
(spyxx {:a 1}) ; `spyxx` prints expression, type, and value
(newline)
(spyxx (java.util.HashMap.)) ; Works
(spyxx (new java.util.HashMap)) ; Works
(newline)
(let [m ^java.util.Map {}]
(spyxx (new java.util.HashMap m)) ; Reflection Warning
(spyxx (java.util.HashMap. m))) ; Reflection Warning
(newline)
(let [^java.util.Map m {}]
(spyxx (new java.util.HashMap m)) ; Works
(spyxx (java.util.HashMap. m)))) ; Works
(def ^java.util.Map m3 {})
(dotest
(newline)
(spyxx m3)
(spyxx (java.util.HashMap. m3))) ; Works
со следующими результатами. Обратите внимание, что все они работают, но вы получаете предупреждение об отражении, где указано выше:
--------------------------------------
Clojure 1.10.2-alpha1 Java 15
--------------------------------------
Testing tst.demo.core
{:a 1} => <#clojure.lang.PersistentArrayMap {:a 1}>
(java.util.HashMap.) => <#java.util.HashMap {}>
(new java.util.HashMap) => <#java.util.HashMap {}>
(new java.util.HashMap m) => <#java.util.HashMap {}>
(java.util.HashMap. m) => <#java.util.HashMap {}>
(new java.util.HashMap m) => <#java.util.HashMap {}>
(java.util.HashMap. m) => <#java.util.HashMap {}>
m3 => <#clojure.lang.PersistentArrayMap {}>
(java.util.HashMap. m3) => <#java.util.HashMap {}>
Кажется, вам не нужна пустая карта Clojure в качестве аргумента конструктора, и тогда проблема исчезнет. Вы также можете убрать предупреждение, установив значение *warn-on-reflection*
false (либо в project.clj
коде, либо вручную в коде).
Если вы используете подсказку типа, ее легко получить в неправильном месте, где она будет молча проигнорирована.
Обновить
Рассмотрим этот дополнительный код:
(dotest
(newline)
(set! *warn-on-reflection* false) ; not executed upon parsing
(let [m4 ^java.util.Map {}]
(spyxx (new java.util.HashMap m4)) ; Reflection Warning
(spyxx (java.util.HashMap. m4)))) ; Reflection Warning
(newline)
; vvv executed when parsed before following lines
(set! *warn-on-reflection* false)
(let [m5 ^java.util.Map {}]
(spyxx (new java.util.HashMap m5)) ; Works
(spyxx (java.util.HashMap. m5))) ; Works
Первый тест генерирует предупреждение об отражении при анализе (перед запуском теста), поскольку анализатор, похоже, оценивает константные выражения (предположение).
2-й тест не генерирует предупреждений, поскольку Clojure читает, анализирует и оценивает каждую форму по очереди. Таким образом, вызов (set! *warn-on-reflection* false)
для отключения предупреждений перед чтением и оценкой следующих строк.
Комментарии:
1. Все более ранние зрители, пожалуйста, просмотрите обновленный ответ на предмет исправлений и дополнительных деталей.