在重构时有没有一种检查返回类型的好方法?

haw*_*eye 5 clojure return-type

目前,当我在Clojure中进行重构时,我倾向于使用这种模式:

(defn my-func [arg1 arg2]
  (assert (= demo.core.Record1 (class arg1) "Incorrect class for arg1: " (class arg1))
  (assert (= demo.core.Record1 (class arg2) "Incorrect class for arg2: " (class arg2))
  ...
Run Code Online (Sandbox Code Playgroud)

也就是说,我发现自己手动检查返回类型,以防系统的下游部分将它们修改为我不期望的东西.(如果我重构并得到一个我不期望的堆栈跟踪,那么我将我的假设表达为不变量,并从那里向前迈进).

从某种意义上说,这正是Bertrand Meyer预期的那种不变检查.(面向对象软件构建的作者,以及契约设计理念的支持者).

挑战是我直到运行时才发现这些.我很乐意在编译时找到它们 - 只需说明函数所期望的内容.

现在我知道 Clojure本质上是一种动态语言.(虽然Clojure有一个"编译器"类型,但我们应该期望值的应用只能在运行时实现.)

我只想要一个好的模式来使重构更容易.(即查看将参数更改为函数的所有流动效果,而不会在第一次调用时看到它中断,然后移动到下一个,然后转到下一个断点.)

我的问题是:在重构时是否有一种检查返回类型的好方法?

leo*_*ges 2

您有几个选项,其中只有一个是“编译”时间:

测试

由于 Clojure 是一种动态语言,因此测试绝对必要。它们是重构时的安全网。即使在静态类型语言中,测试仍然有用。

前置条件和后置条件

它们允许您通过向函数添加元数据来验证不变量,例如来自Michael Fogus 博客的示例:

(defn constrained-fn [f x]
  {:pre  [(pos? x)]
   :post [(= % (* 2 x))]}
  (f x))

(constrained-fn #(* 2 %) 2)
;=> 4
(constrained-fn #(float (* 2 %)) 2)
;=> 4.0
(constrained-fn #(* 3 %) 2)
;=> java.lang.Exception: Assert failed: (= % (* 2 x)
Run Code Online (Sandbox Code Playgroud)

核心类型

core.typed是此列表中唯一可以为您提供编译时间检查的选项。然后你的例子将像这样表达:

(ann  my-func (Fn [Record1 Record1 -> ResultType]))
(defn my-func [arg1 arg2]
...)
Run Code Online (Sandbox Code Playgroud)

这是以将 core.typed 作为单独的操作运行为代价的,可能作为测试套件的一部分。

仍然在运行时验证/检查领域,还有更多选项,例如ouncerschema