【发布时间】:2026-01-12 09:05:01
【问题描述】:
我正在编写一个 clojure 库,并且正在考虑使用 clojure.spec。使用规范/有效是一种好习惯吗?在运行时输入函数?还是我应该使用破坏性和类型提示?我担心是否会有性能损失,是否被认为是对规范的不当使用,以及通常是不好的做法。
【问题讨论】:
标签: clojure clojure.spec
我正在编写一个 clojure 库,并且正在考虑使用 clojure.spec。使用规范/有效是一种好习惯吗?在运行时输入函数?还是我应该使用破坏性和类型提示?我担心是否会有性能损失,是否被认为是对规范的不当使用,以及通常是不好的做法。
【问题讨论】:
标签: clojure clojure.spec
“在适当的情况下”检查有效输入总是合适的。这意味着什么?这是一个悬而未决的问题。
一般来说,最“危险”的输入来自外部世界,位于程序的边界。这意味着来自网络/浏览器的输入,或者可能来自其他服务。
“最安全”的输入在您的程序深处,在那里(大概)您有更多的控制权和信心。例如,您(可能)永远不会检查 + 函数的输入以确保每个 arg 都是一个数字。而且,即使一个无效的参数(可能是一个字符串)溜过,JVM 也会立即抛出一个异常。
当然,您应该在运行单元测试时进行最大程度的检查,因此至少您知道您的代码在“正常”路径中正常工作。我喜欢为此使用Plumatic Schema,因为在单元测试期间始终运行验证很容易,但在“生产”运行期间默认关闭。
话虽如此,我经常将断言语句放在函数的开头,因为错误的输入很难识别,或者以后真的会导致难以诊断的问题。
这两种技术救了我很多次!
请注意,即使是像 Java 这样的强类型语言也无法将您保存在这里。类型化变量可以确保输入是一个数字,但它可能是无效的,例如向sqrt 函数发送一个负值。其他函数可能有更严格的输入,例如仅对素数有效等。类型无法捕获这些详细要求。只有好的设计和好的测试才能避免这些问题。
类型和断言不能防止所有问题,但它们就像道路上的护栏(或安全带和安全气囊)。它们可能无法防止碰撞,但可以提供早期预警并降低后果的严重性。
附:您可以看到我喜欢如何平衡安全性和签入a libary I wrote 的成本之间的权衡。请务必see the file _bootstrap.clj,这是仅在单元测试期间打开 Plumatic Schema 测试的技巧。
【讨论】: