我正在根据用户输入来调用函数,但是有些具有两个参数,而其他参数只有一个。不是在每个函数上都使用&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)))))
如果用户输入是“装备剑”,我需要通过传递'(“ Sword”)作为参数来调用函数“ equip”,但是如果用户输入是“ status”,则需要调用函数“状态”而不传递“ args”,而不是将其传递为“ NIL”
答案 0 :(得分:4)
我认为您想使用apply
而不是funcall
,
find-symbol
代替
read-from-string
(这实际上对security reasons很重要!)
和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)
...)
答案 1 :(得分:1)
您还可以使用简单的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))))