当我在Common Lisp中定义一个函数时,如下所示:
(defun foo (n)
(declare (type fixnum n))
(+ n 42))
我本以为像(foo "a")
这样的调用会立即失败,但在调用+
时却失败了。declare
表单是否不能保证静态类型检查?
类型声明传统上是用来作为编译器优化目的的保证。对于类型检查,请使用check-type
(但请注意,它也在运行时进行检查,而不是在编译时):
(defun foo (n)
(check-type n fixnum)
(+ n 42))
也就是说,不同的Common Lisp实现对类型声明的解释不同。例如,如果safety
策略设置足够高,则SBCL会将它们视为要检查的类型。
此外,如果你想要静态检查,SBCL可能也是你的最佳选择,因为它的类型推理引擎会警告你它遇到的任何不一致。为此,ftype
声明可以得到很好的利用:
CL-USER(1): (declaim (ftype (function (string) string) bar))
CL-USER(2): (defun foo (n)
(declare (type fixnum n))
(bar n))
; in: DEFUN FOO
; (BAR N)
;
; caught WARNING:
; Derived type of N is
; (VALUES FIXNUM &OPTIONAL),
; conflicting with its asserted type
; STRING.
; See also:
; The SBCL Manual, Node "Handling of Types"
;
; compilation unit finished
; caught 1 WARNING condition
FOO
声明只是编译器的提示,因此它可以生成更高效的代码。换句话说,它不是静态检查。