Для этого класса Java в качестве примера:
package foo;
public class TestInterop
{ public String test(int i)
{ return "Test(int)"; }
public String test(Object i)
{ return "Test(Object)"; }
}
Когда я запускаю Clojure и пытаюсь назвать тест (интервал) метод, тест (Объект), метод называют вместо этого, потому что Clojure автоматически поля целое число в java.lang. Целочисленный объект.
Как я вынуждаю Clojure назвать тест (интервал) метод?
user=> (.test (new foo.TestInterop) 10)
"Test(Object)"
Я хочу назвать методы как Component.add(Component comp, int index)
в AWT, но вместо этого продолжают звонить add(Component comp, Object constraints)
, таким образом, кнопки на моей панели инструментов всегда появляются в неправильном порядке.
На канале #clojure на Freenode только что идет обсуждение этой самой темы. Крис Хаузер (который собирался опубликовать ответ, но в конце концов решил, что он слишком занят, чтобы сделать это) опубликовал Gist , который демонстрирует, что происходит с логическим значением
vs. Перегруженный метод объекта
; оказывается, что в некоторых сценариях в дополнение к приведению типа (boolean ...)
требуется подсказка типа. Обсуждение было весьма поучительным, несколько темных уголков процесса компиляции Clojure стали хорошо освещены. (См. Ссылки на журнал IRC ниже.)
В основном, если объект создается прямо в форме вызова метода - (. Foo (Foo.) ...)
, скажем, - то подсказка типа не требуется; это также не обязательно, если объект был сконструирован как значение для локального значения во включающей форме let
(см. обновление 2 ниже и мою версию Gist). Однако, если объект получен с помощью поиска Var, требуется подсказка типа, которая может быть предоставлена либо на самом Var, либо на месте вызова на символе, используемом для ссылки на Var.
Код Java из Gist:
package mypkg;
public class Ugly {
public Ugly(){}
public String foo(boolean i) { return "bool: " + i; }
public String foo(Object o) { return "obj: " + o; }
}
И код Clojure:
(.foo (mypkg.Ugly.) 5)
;=> "obj: 5"
(.foo (mypkg.Ugly.) true)
;=> "obj: true"
(.foo (mypkg.Ugly.) (boolean true))
;=> "bool: true"
(def u (mypkg.Ugly.))
(.foo u (boolean true))
;=> "obj: true"
(.foo #^mypkg.Ugly u (boolean true))
;=> "bool: true"
Обратите внимание, что компилятору Clojure требуется указание типа на u
, чтобы иметь возможность скомпилировать прямой вызов метода. В противном случае создается впечатление, что создается основанный на отражении код, который, по-видимому, упускает из виду тот факт, что аргумент должен быть примитивным на этом пути.
Мои дополнения следуют (а вот мой ответвитель вышеупомянутого Gist ).
;; renamed mypkg.Ugly to foo.TestInterop2 when doing my tests
user> (let [t (foo.TestInterop2.)]
(.foo t (boolean true)))
"bool: true"
;;; type-hinting the Var
user> (def #^foo.TestInterop2 x (foo.TestInterop2.))
#'user/x
user> (.foo x (boolean true))
"bool: true"
Эта тема впервые была поднята на этом этапе .Чаузер разместил Gist через полчаса , и после этого обсуждение становилось все более и более интересным.
user=> (.test (foo.TestInterop.) 10)
"Test(Object)"
user=> (.test (foo.TestInterop.) (int 10))
"Test(int)"
Числа в Clojure обычно заключены в рамку (int => Integer), если вы специально не запрашиваете примитивы.
Здесь есть дополнительная информация о примитивах в Clojure.