^ 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中枚举的接口(当前)仅限于任意数量的对象(盒装类型)以及最多四种doublelong精度类型的组合。 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);}

每种新的支持类型都会增加许多新的接口(指数增长)。 这就是为什么只支持最广泛的原始类型: longdouble

链接地址: http://www.djcxy.com/p/14487.html

上一篇: ^char type hint not permitted for clojure defn parameter

下一篇: Determine if the device has touch screen or not