2024年Clojure状态调查!中分享你的想法。

欢迎!请参阅关于页面以了解更多有关该功能的详细信息。

+2
编译器

在类型提示的参考文档(https://clojure.org/reference/java_interop#typehints)中,指出可以在参数向量之前放置类型提示来提示函数的返回类型
(defn hinted-single ^String [])

然而,在变量名本身之前放置提示似乎具有相同的效果

(defn ^String hinted-var [])

例如,以下代码不会产生反射警告
(set! *warn-on-reflection* true) (fn [] (hinted-var .length))

这是否是正确的预期行为?例如,这是在clojure.string中的大多数函数中使用的: https://github.com/clojure/clojure/blob/653b8465845a78ef7543e0a250078eea2d56b659/src/clj/clojure/string.clj#L48

2个回答

+3

请注意,你在链接的文档页面上的一个示例显示了具有不同返回类型提示的多参数函数定义。这是通过在参数向量上放置返回类型提示来实现的。

(defn hinted
  (^String [])
  (^Integer [a])
  (^java.util.List [a & args]))

该页面还提到,类型提示可以放置在“变量名(当定义时)“,这就是你在clojure.string命名空间中看到多次使用的原因。

这些位置中类型提示的区别在于,编译器会在var名称上评估元数据表达式,如本页文档所述https://clojure.org/reference/special_forms,但不会在arg vector上评估。可能在其他地方也不会进行评估,但我还没有对此进行深入研究。

Eastwood lint工具的文档中,其关于`:wrong-tag` linters的文档中有关于Clojure代码中有用和无关的类型提示的许多详细信息。https://github.com/jonase/eastwood#wrong-tag

这也在`:unused-meta-on-macro` linters的文档中进行说明。https://github.com/jonase/eastwood#unused-meta-on-macro

by
感谢您的回复!

那么这是否意味着函数返回类型从其var的标签中推断出来是官方正确的行为?
虽然Eastwood文档同意这一点,但这并不等同于官方语言规范(这就是为什么我在这个论坛上提问的原因)

您在clojure.org文档中提到的句子并没有明确说明给_function_变量浇水会提示其返回类型还是函数对象本身

> 它们可以放置在函数参数、let-bound名称、var名称(在定义时)和表达式上

毕竟`defn`宏会展开成`def`形式,在`def`变量上放置类型提示则指的是存储在变量中的值的类型。
因此,对于函数变量的类型提示来说,同时有两种解释以及存在多个提示返回类型的语法槽似乎显得有些奇怪和混乱。
by
我无法对Clojure做官方声明。世界上大约有三个人可以。我可以告诉你Clojure现在是如何工作的,以及在它的大部分存在期间是如何工作的,即函数变量上的类型提示确实是指示了它的返回类型,正如你从实验中发现的那样。
by
这类返回类型提示的首选位置(也是错误率较低的)是在arg签名上,而不是在var上。
0 投票

编辑

当在用 defn 声明的函数上类型注解返回类型时,Clojure 支持两种有效位置:

在 var 上

(defn ^String hello []
  "Hello")

或在 arg-vector 上

(defn hello ^String []
  "Hello")

尽管如此,前一种方法从未被优先考虑。也就是说,您实际上应该在 arg-vector 中进行类型注解,以下是一些原因:

  1. 当您在 var 上进行类型注解时,注解将被评估。因此,您不能对原始类型进行类型注解,因为 ^long 会解析为 long 函数,而不是类型。所以对于原始类型注解,这实际上不起作用。

  2. 如果您有一个多态函数,其中不同的多态性返回不同的类型,只有后者语法允许您对所有类型进行适当的注解。

  3. 在存在两种注解的情况下,将使用 arg-vector 注解。

  4. 在 var 上的注解对于阅读代码的程序员来说是模糊的,您是在注解函数的返回值还是在 var 中的值(在这种情况下将是一个函数)。Clojure 将将其用作返回值的提示,但由于对于 def 注解是关于 var 中的值,而相对于 defn 注解将是关于 var 中函数的返回值,这可能会造成混淆。

因此,我建议始终通过向 arg-vector 添加提示来注解返回值,即使两种方法都可以工作。

您仍然可以在 var 上进行原始类型的类型注解,只是不使用那种语法

(def ^{:tag 'long} b 1)
by
那么,为什么有两种方法呢?
by
有时候,需要类型提示来自一个已经评估的表达式。我相当确定var上的返回类型提示是首先出现的,arglist上的类型提示是后来添加的,Clojure从不轻易移除任何东西,以免更新破坏任何人的代码。
...