我需要从数据库中读取一串 Common Lisp 对象。对象应该是一个包含两个双浮点元素的列表; “(1.0d0 2.0d0)”例如:
(let* ((str "(1d0 2d0)")
(off (read-from-string str)))
(destructuring-bind (x y)
off (list x y)))
但是也有字符串格式不正确的情况?例如,查询失败,或对象不存在。代码将给出 arg-count-error:
error while parsing arguments to DESTRUCTURING-BIND:
too few elements in
()
to satisfy lambda list
(X Y):
exactly 2 expected, but got 0
[Condition of type SB-KERNEL::ARG-COUNT-ERROR]
我必须使用以下代码进行类型检查。
(let* ((str "(1d0 2d0)")
(off (read-from-string str)))
(destructuring-bind (x y)
(if (and off
(typep off 'list)
(= 2 (length off)))
off
(list 0d0 0d0)) (list x y)))
如果 str 格式不正确,代码片段将返回默认值。 : (0.0d0 0.0d0) ;
我做得对吗?
有没有更好的方法来避免这个错误?
最佳答案
有几种方法可以解决这个问题。一种选择是使用模式匹配库(例如 Trivia )。
(defun read-coord (string)
(match (read-from-string string nil)
((list x y) (list x y))
(_ (list 0d0 0d0))))
CL-USER> (read-coord "(1d0 2d0)")
(1.0d0 2.0d0)
CL-USER> (read-coord "(1d0)")
(0.0d0 0.0d0)
CL-USER> (read-coord "")
(0.0d0 0.0d0)
如果要检查
X
和 Y
是否为浮点数,可以添加保护模式(defun read-coord (string)
(match (read-from-string string nil)
((list (guard x (floatp x))
(guard y (floatp y)))
(list x y))
(_ (list 0d0 0d0))))
正如 Rainer Joswig 在 his answer 中指出的那样,
READ-FROM-STRING
会导致其他错误,读取时应将 *READ-EVAL*
设置为 NIL
。(defun safely-read-from-string (string)
(let ((*read-eval* nil))
(ignore-errors (read-from-string string))))
(defun read-coord (string)
(match (safely-read-from-string string)
((list (guard x (floatp x))
(guard y (floatp y)))
(list x y))
(_ (list 0d0 0d0))))
还请记住,您可以将 lambda 列表关键字(例如
&OPTIONAL
)与 DESTRUCTURING-BIND
一起使用。使用 Alexandria 作为 ENSURE-LIST
函数,你可以写(defun read-coord (string)
(destructuring-bind (&optional (x 0d0) (y 0d0) &rest _)
(ensure-list (safely-read-from-string string))
(declare (ignore _))
(list x y)))
CL-USER> (read-coord "(1d0 2d0)")
(1.0d0 2.0d0)
CL-USER> (read-coord "(1d0)")
(1.0d0 0.0d0)
CL-USER> (read-coord "")
(0.0d0 0.0d0)
如果你不想使用任何库,你可以自己检查一个列表
(defun read-coord (string)
(let ((coord (safely-read-from-string string)))
(destructuring-bind (&optional (x 0d0) (y 0d0) &rest _)
(if (listp coord)
coord
(list coord))
(declare (ignore _))
(list x y))))
关于common-lisp - 如何避免解构绑定(bind) ARG-COUNT-ERROR?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41156543/