^ char类型提示不允许clojure defn参数
观察以下repl会话:
user=> (set! *warn-on-reflection* true)
true
user=> (defn blah [s] (for [c s] (if (Character/isDigit c) true false)))
Reflection warning, NO_SOURCE_PATH:1:31 - call to isDigit can't be resolved.
Reflection warning, NO_SOURCE_PATH:1:31 - call to isDigit can't be resolved.
#'user/blah
user=> (blah "abc123abc")
(false false false true true true false false false)
user=> (defn blah [s] (for [^char c s] (if (Character/isDigit c) true false)))
#'user/blah
user=> (blah "abc123abc")
(false false false true true true false false false)
  所以我们使用了一个^char类型的提示来摆脱反射 - 太棒了。  现在在函数参数中尝试同样的事情: 
user=> (defn blah-c [c] (if (Character/isDigit c) true false))
Reflection warning, NO_SOURCE_PATH:1:22 - call to isDigit can't be resolved.
#'user/blah-c
user=> (defn blah-c [^char c] (if (Character/isDigit c) true false))
CompilerException java.lang.IllegalArgumentException: Only long and double primitives are supported, compiling:(NO_SOURCE_PATH:1:1) 
user=> (defn blah-c [^Character c] (if (Character/isDigit c) true false))
#'user/blah-c
user=> (blah-c 1)
true
user=> (blah-c a)
false
  我知道Clojure只支持数字原语的长或双类型提示,并且Java char是数字数据类型 - 不需要解释这一点。  但上面看起来不一致 - 在for的第一个函数中允许使用类型提示^char ,但不能在blah-c的函数签名中使用,这里我必须指定Character 。  这是什么原因(即从编译器实现的角度来看)? 
  的type-暗示for您正在标记表达c作为char作为提示给编译器。  当编译器发出isDigit的(静态)方法时,它知道你想要接受一个char的版本(而不是int版本)。  字节码被发送到实现IFn接口的O (单个Object参数)版本的函数对象中(所有参数默认都是装箱的)。 
  在另一种情况下, blah-c ,需要将字节码发送给实现IFn接口不存在的C (例如, char )版本的函数对象。  可以有每个原始的接口吗?  当然,但没有。  对于每种可能的组合?  由于组合爆炸,不可行。 
  你可以说,那么,为什么不直接将blah-c发送到O接口呢?  这将打破函数参数的类型提示点,这是为了避免装箱/取消装箱,因为字符原语必须被装箱才能进行调用。  函数参数的类型提示点不仅仅是为了避免反射。  如果你想在这里避免反射,那么你不会标记函数参数,而是在进行isDigit调用之前将它强制转换为let块中的char 。 
  请注意,clojure.lang.IFn中枚举的接口(当前)仅限于任意数量的对象(盒装类型)以及最多四种double和long精度类型的组合。  double版本和long版本作为优化提供,以避免在基元上编写性能关键代码时进行装箱/取消装箱,并且应该足以满足大多数目的。 
这是基于@A的评论。 Webb和@kotarak,据我了解他们。
  这有两个方面:首先,为什么^char在某些情况下可用(例如for )?  这不仅是优化所必需的,而且正如您的示例所示,正确的Java互操作。  另外,它看起来(对我来说)实施相对便宜,因为每个变量都是独立的,所以它可以自行处理。 
对于函数定义,情况并非如此,对于支持类型的每种组合,您必须定义一个新接口:例如,
static public interface L{long invokePrim();}
static public interface D{double invokePrim();}
static public interface OL{long invokePrim(Object arg0);}
// ...
static public interface OLD{double invokePrim(Object arg0, long arg1);}
// all the way to
static public interface DDDDD{double invokePrim(double arg0, double arg1, double arg2, double arg3);}
  每种新的支持类型都会增加许多新的接口(指数增长)。  这就是为什么只支持最广泛的原始类型: long和double 。 
上一篇: ^char type hint not permitted for clojure defn parameter
