ClojureScript

1.10.516 版本发布

2019 年 1 月 31 日
ClojureScript 团队

值得注意的变更

Spec 检测 (cljs.spec.test.alpha/instrument 和相关功能) 不再需要 test.check。如果您使用 cljs.spec.test.alpha/check,则需要 test.check 的数据生成功能;在这种情况下,您需要引入 clojure.test.checkclojure.test.check.properties 命名空间。

cljs.spec.test.alpha/check API 中与 Spec 使用 test.check 相关的关键字现在使用 clojure.spec.test.check 限定,与 Clojure 保持一致。之前使用 clojure.test.check 限定的方式仍然受支持。

Clojure 1.10 功能

改进的异常信息和打印

Clojure 1.10 中添加的 改进的异常基础设施 已在此版本中移植到 ClojureScript。

通过元数据使用协议

使用元数据添加协议的能力(对于使用 :extend-via-metadata true 指令定义的协议)已在此版本中移植到 ClojureScript。

Datafy 和 Nav

clojure.datafy 命名空间已移植到 ClojureScript,以及 clojure.core.protocols 命名空间中的相关协议。

clojure.edn 命名空间

此版本添加了新的 clojure.edn 命名空间,它将功能委托给 cljs.reader。这有助于编写使用 clojure.edn/readclojure.edn/read-string 的可移植 Clojure/ClojureScript 源代码。

类型推断改进

谓词诱导类型推断

类型推断算法现在将考虑核心谓词,以便推断条件表达式中使用的局部变量的类型。

例如,在

(if (string? x)
  (inc x)
  10)

因为 x 满足 string?,所以在 then 分支中它将被推断为字符串类型(因此会发出警告,因为 inc 正在对其进行应用)。

因为 condwhen 是基于 if 构建的宏,所以谓词诱导推断也对涉及 condwhen 的表达式按预期工作。

除了核心谓词之外,谓词诱导类型推断也适用于 instance? 检查。因此,例如,测试 (instance? Atom x) 将导致 x 被推断为 cljs.core/Atom 类型。

真值诱导推断

在值可能为 nil(在类型标签中表示为符号 clj-nil)的情况下,如果引用此类值的简单符号用作条件中的测试,类型推断算法将推断出该值在 then 分支中不可能为 nil

这也许可以通过一个例子来说明。假设您有以下函数

(defn f [x]
  (when (even? x)
    (inc x)))

此函数的返回值类型为 #{number clj-nil},这意味着它可以返回数字或 nil

以下函数使用 f,之前被推断为返回 #{number clj-nil},现在被推断为返回 number

(defn g [y]
  (let [z (f y)]
    (if z
      z
      17)))

事实上,由于 or 宏的展开方式,表达式 (or (f 1) 17) 现在被推断为仅仅是 number

改进的 loop / recur 推断

类型推断算法现在将考虑 recur 参数类型,以便推断 loop 局部变量类型。

例如,在

(loop [x "a"]
  (if (= "a" x)
   (recur 1)
   (+ 3 x)))

局部变量 x 之前被推断为字符串类型(这会导致表达式将它添加到 3 中发出警告)。现在,编译器将推断 x 为字符串或数字类型(因此警告将不再出现)。

多参数和变长函数返回值类型推断

ClojureScript 1.10.439 添加了 函数返回值类型推断,但此功能仅适用于单参数函数。此版本将此功能扩展到多参数和变长函数。

此外,如果不同的参数数量返回不同的类型,推断的返回值类型将正确地变化。例如,

(defn foo
  ([x] 1)
  ([x y] "a"))

那么表达式 (foo true) 将被推断为数字类型,而 (foo :a :b) 将被推断为字符串类型。

Spec 改进

此版本对 Spec 实现进行了多项改进,使其更容易对标准核心库中的函数进行 Spec,并且在代码库中大量函数具有 Spec 时,还提高了检测性能。

性能提升

对范围的 Chunked-Seq 支持

ClojureScript 现在支持对范围的 chunked-seq。此功能提高性能的一个例子是

(reduce + (map inc (map inc (range (* 1024 1024)))))

在 V8 中它的执行速度提高了 5 倍,在 SpiderMonkey 中提高了 7 倍,在 JavaScriptCore 中提高了 2 倍。

改进的 re-seq 性能

re-seq 性能已经得到提升,在主要 JavaScript 引擎下速度提高了 1.5 倍或更多。

优化的字符串表达式连接

通常,传递给 str 函数的参数在连接之前首先被强制转换为字符串。在此版本中,对于被推断为字符串类型的参数,会消除不必要的强制转换,从而导致更紧凑的代码生成,以及速度提升。

例如,在

(defn foo [x y]
  (str (+ x y)))

(str (name :foo/bar) "-" (foo 3 2))

由于改进的代码生成,最后一个 str 表达式在 V8 中执行速度提高了 3 倍,在 JavaSriptCore 中提高了 4 倍。

变更列表

有关 ClojureScript 1.10.516 中所有更新的完整列表,请参阅 变更

贡献者

感谢所有为 ClojureScript 1.10.516 做出贡献的社区成员

  • Anton Fonarev

  • Enzzo Cavallo

  • Erik Assum

  • Eugene Kostenko

  • Martin Kučera

  • Michiel Borkent

  • Oliver Caldwell

  • Sahil Kang

  • Thomas Heller

  • Thomas Mulvaney

  • Timothy Pratley

  • Will Acton