我根据用户输入调用函数,但有些有两个参数,有些只有一个。与其在每个函数上使用 &optional 参数(并且从不使用它),有没有办法在参数的值为"NIL"时简单地不传递参数?
这适用于交互式小说游戏,其中用户键入一些命令,这些命令被转换为函数调用。
(defun inputs (state)
(format *query-io* "> ")
(force-output *query-io*)
(let* ((entry (cl-ppcre:split "\s+" (string-downcase (read-line *query-io*))))
(function (car entry))
(args (cdr entry)))
(if (valid-call function)
(funcall (symbol-function (read-from-string function))
state
args)
(progn
(format *query-io* "Sorry, I don't know the command '~a'~%~%" function)
(inputs state)))))
如果用户输入是"装备剑",我需要调用函数"装备",传递'("剑")作为参数,但如果用户输入是"状态",我需要调用函数"状态"而不传递'args',而不是将它们作为"NIL"传递
我想你想用apply
而不是funcall
, find-symbol
而不是 read-from-string
(出于安全原因,这实际上很重要!和destructuring-bind
而不是let*
:
(defun inputs (state)
(format *query-io* "> ")
(force-output *query-io*)
(destructuring-bind (command &rest args)
(cl-ppcre:split "\s+" (string-downcase (read-line *query-io*)))
(if (valid-call command)
(apply (find-symbol command) state args)
(progn
(format *query-io* "Sorry, I don't know the command '~a'~%~%" command)
(inputs state)))))
使用 apply
可以让命令接受任意数量的参数,而不是一个参数。
事实上,您的valid-call
可能应该返回要调用的函数:
(let ((f (valid-call function)))
(if f
(apply f state args)
...)
您还可以使用简单的LOOP
而不是递归调用:
(defun inputs (state)
(loop
(format *query-io* "> ")
(force-output *query-io*)
(let* ((entry (cl-ppcre:split "\s+" (string-downcase (read-line *query-io*))))
(function (car entry))
(args (cdr entry)))
(when (valid-call function)
(apply (symbol-function (find-symbol function))
state
args)
(return))
(format *query-io* "Sorry, I don't know the command '~a'~%~%" function))))