如何获取Common Lisp函数的参数数量?附测试库适配场景
实现函数参数统计与同步/异步测试调度
看起来你是要把JavaScript测试库的逻辑搬到Common Lisp里,核心需要先搞定「获取函数参数个数」的能力,再用它区分同步和异步测试——思路很清晰,咱一步步来实现。
第一步:实现获取函数参数数量的工具函数
Common Lisp本身没有直接的length-args函数,但我们可以用function-lambda-list来获取函数的lambda列表,再统计参数数量。先写最基础的版本:
(defun get-count-args-func (func) (length (function-lambda-list func)))
测试你给的示例:
(defun func1 (arg1 arg2) ()) (get-count-args-func #'func1) ; 直接返回2,完美符合预期
如果你的测试函数可能包含可选参数、关键字参数这类特殊情况,可以优化成只统计必填的位置参数——毕竟异步测试一般都是明确需要一个done回调作为必填参数的:
(defun get-required-arg-count (func) (let ((lambda-list (function-lambda-list func))) (length (loop for elem in lambda-list until (member elem '(&optional &rest &key &aux &allow-other-keys)) collect elem))))
这个版本会忽略&optional及之后的所有特殊标记和参数,只统计前面的必填位置参数,更贴合测试场景的需求。
第二步:实现同步/异步测试的调度逻辑
有了参数统计函数,就能实现你要的run-test逻辑了。先放完整的代码示例,包括测试函数和回调:
;; 示例同步测试函数:不需要done回调 (defun test-sync () (format t "执行同步测试...~%")) ;; 示例异步测试函数:需要接收done回调 (defun test-async (done) (format t "执行异步测试...~%") (funcall done) ; 异步操作完成后调用done标记结束 ) ;; 测试完成的回调函数 (defun done () (format t "测试已完成!~%")) ;; 核心测试调度函数 (defun run-test (test) (if (>= (get-required-arg-count test) 1) (funcall test #'done) ; 异步测试:传入done回调 (funcall test))) ; 同步测试:直接执行
逻辑说明:
- 当测试函数的必填参数个数≥1时,判定为异步测试,调用时传入
done回调,让测试在完成后主动触发结束信号 - 当测试函数没有必填参数时,判定为同步测试,直接执行即可
小提示
如果你的测试函数是用lambda定义的闭包,function-lambda-list同样能正常工作,比如:
(defun test-closure (done) (let ((internal-val 42)) (format t "闭包测试:~a~%" internal-val) (funcall done))) (get-required-arg-count #'test-closure) ; 返回1,没问题
内容的提问来源于stack exchange,提问作者PerduGames
相关产品推荐
相关产品推荐

