clojure函数调用隐藏类型信息

clojure函数调用隐藏类型信息,clojure,clojure-java-interop,Clojure,Clojure Java Interop,我有一个用于调试的小函数: (set! *warn-on-reflection* true) (defn debug [x] (doto x (->> println :>))) 当我在循环中调用我的函数时,我得到以下反射警告: (loop [i 5] (when (pos? i) (recur (debug (dec i))))) form-init14269737395101875093.clj:1 recur arg for primitive local: i i

我有一个用于调试的小函数:

(set! *warn-on-reflection* true)

(defn debug [x] (doto x (->> println :>)))
当我在循环中调用我的函数时,我得到以下反射警告:

(loop [i 5] (when (pos? i) (recur (debug (dec i)))))

form-init14269737395101875093.clj:1 recur arg for primitive local: i is not matching primitive, had: Object, needed: long
Auto-boxing loop arg: i
(.add (debug2 (ArrayList.)) 5)

我想解决反射警告。如何使函数“继承”参数中的类型信息而不显式指定它或用宏替换它?

以下是一种有效的方法:

(loop [i (Integer. 5)]
  (when (pos? i)
    (recur (debug (dec i)))))
无警告结果:

lein test tst.demo.core
4
3
2
1
0
看起来只使用普通
5
会导致编译器使用不能暗示类型的原语。显式创建一个
整数
对象可以避免这个问题。我还尝试了
(int 5)
,但没有成功

是否有理由要打开反射警告?我通常从不使用它们,特别是在调试时


更新

请注意,如果将代码包装在如下函数中:

(defn stuff
  [arg]
  (loop [i arg]
    (when (pos? i)
      (recur (debug (dec i))))))

调用
(stuff 5)
没有问题,因为函数参数必须始终作为对象传递(必要时通过自动装箱)。

以下是一种有效的方法:

(loop [i (Integer. 5)]
  (when (pos? i)
    (recur (debug (dec i)))))
无警告结果:

lein test tst.demo.core
4
3
2
1
0
看起来只使用普通
5
会导致编译器使用不能暗示类型的原语。显式创建一个
整数
对象可以避免这个问题。我还尝试了
(int 5)
,但没有成功

是否有理由要打开反射警告?我通常从不使用它们,特别是在调试时


更新

请注意,如果将代码包装在如下函数中:

(defn stuff
  [arg]
  (loop [i arg]
    (when (pos? i)
      (recur (debug (dec i))))))

调用
(stuff 5)
没有问题,因为函数args必须始终作为对象传递(如果需要,通过自动装箱)。

问题是无法推断
调试的返回类型

这通常通过以下方法解决:

在您的情况下,以下几点可以做到:

(defn debug ^long [x] (doto x (->> println :>)))

user> (loop [i 5] (when (pos? i) (recur (debug (dec i)))))
4
3
2
1
0
nil

问题是无法推断
debug
的返回类型

这通常通过以下方法解决:

在您的情况下,以下几点可以做到:

(defn debug ^long [x] (doto x (->> println :>)))

user> (loop [i 5] (when (pos? i) (recur (debug (dec i)))))
4
3
2
1
0
nil

如果出于任何原因,您不想使用宏,则可能需要查看似乎保留类型信息的宏:

(definline debug2 [x] (doto x (->> println :>)))
例如,下面的调用不会导致反射警告:

(loop [i 5] (when (pos? i) (recur (debug (dec i)))))

form-init14269737395101875093.clj:1 recur arg for primitive local: i is not matching primitive, had: Object, needed: long
Auto-boxing loop arg: i
(.add (debug2 (ArrayList.)) 5)
我最初的想法是使用一个带有重载方法的Java类来实现类似的东西,其中一个方法将接受一个泛型参数
T
,并返回一个
T
。除此泛型方法外,您还必须为少数基本类型重载该方法,因为泛型仅适用于装箱值AFAIK。然后可以重用下面的类进行调试:

import clojure.lang.IFn;

public class PassThrough {
    private IFn _fn;
    
    public PassThrough(IFn fn) {
        _fn = fn;
    }

    public <T> T invoke(T x) {
        _fn.invoke(x);
        return x;
    }

    public long invoke(long x) {
        _fn.invoke(x);
        return x;
    }
    
    public double invoke(double x) {
        _fn.invoke(x);
        return x;
    }
}
导入clojure.lang.IFn;
公共类直通{
私人干扰素;
公共直通车(IFn fn){
_fn=fn;
}
公共T调用(T x){
_fn.援引(x);
返回x;
}
公共长调用(长x){
_fn.援引(x);
返回x;
}
公共双调用(双x){
_fn.援引(x);
返回x;
}
}
但是,由于类型擦除,这对引用类型不起作用。所以如果我这样做,我仍然会得到一个警告:

(defn debug [x] (doto x (->> println :>)))
(def pt-debug (PassThrough. debug))
(.add (.invoke ^PassThrough pt-debug (ArrayList.)) 9) ;; <-- Reflection warning here when calling .add
(defn debug[x](doto x(->println:>))
(def pt debug(PassThrough.debug))

(.add(.invoke^PassThrough pt debug(ArrayList.)9) 如果出于任何原因,您不想使用宏,则可能需要查看似乎保留类型信息的宏:

(definline debug2 [x] (doto x (->> println :>)))
例如,下面的调用不会导致反射警告:

(loop [i 5] (when (pos? i) (recur (debug (dec i)))))

form-init14269737395101875093.clj:1 recur arg for primitive local: i is not matching primitive, had: Object, needed: long
Auto-boxing loop arg: i
(.add (debug2 (ArrayList.)) 5)
我最初的想法是使用一个带有重载方法的Java类来实现类似的东西,其中一个方法将接受一个泛型参数
T
,并返回一个
T
。除此泛型方法外,您还必须为少数基本类型重载该方法,因为泛型仅适用于装箱值AFAIK。然后可以重用下面的类进行调试:

import clojure.lang.IFn;

public class PassThrough {
    private IFn _fn;
    
    public PassThrough(IFn fn) {
        _fn = fn;
    }

    public <T> T invoke(T x) {
        _fn.invoke(x);
        return x;
    }

    public long invoke(long x) {
        _fn.invoke(x);
        return x;
    }
    
    public double invoke(double x) {
        _fn.invoke(x);
        return x;
    }
}
导入clojure.lang.IFn;
公共类直通{
私人干扰素;
公共直通车(IFn fn){
_fn=fn;
}
公共T调用(T x){
_fn.援引(x);
返回x;
}
公共长调用(长x){
_fn.援引(x);
返回x;
}
公共双调用(双x){
_fn.援引(x);
返回x;
}
}
但是,由于类型擦除,这对引用类型不起作用。所以如果我这样做,我仍然会得到一个警告:

(defn debug [x] (doto x (->> println :>)))
(def pt-debug (PassThrough. debug))
(.add (.invoke ^PassThrough pt-debug (ArrayList.)) 9) ;; <-- Reflection warning here when calling .add
(defn debug[x](doto x(->println:>))
(def pt debug(PassThrough.debug))

(.add(.invoke^PassThrough pt debug(ArrayList.)9);;很多人总是在他们所有的代码中启用反射警告,并建议其他人也这样做。反射会影响性能,因此有很好的理由希望至少在代码中注意到它。很多人总是在所有代码中启用反射警告,并建议其他人也这样做。反射会影响性能,因此有很好的理由至少在代码中注意到它。我很好奇:为什么宏不可接受?我很好奇:为什么宏不可接受?