我想在另一个名称很长的包中使用一些函数(例如,“sb-bsd-sockets”),我必须这样写:
(defun myfun (...)
(sb-bsd-sockets:socket-bind ...)
(sb-bsd-sockets:socket-listen ...)
...)
有没有办法导入其中一些仅在内部可用的符号myfun
(没有任何性能损失)?
我想在另一个名称很长的包中使用一些函数(例如,“sb-bsd-sockets”),我必须这样写:
(defun myfun (...)
(sb-bsd-sockets:socket-bind ...)
(sb-bsd-sockets:socket-listen ...)
...)
有没有办法导入其中一些仅在内部可用的符号myfun
(没有任何性能损失)?
以下是我脑海中闪现的第一件事(简单的树遍历和符号名称替换)。
应该注意的是,问题是关于导入符号的,以下内容没有这样做。它只是为您添加了丑陋的 package-name:: 部分。
(defmacro with-symbols-from ((package-name &rest symbols) &body body)
(let ((f-symbols (loop :for s :in symbols :collect
(intern (symbol-name s) package-name))))
`(progn
,@(loop :for symbol :in symbols :for f-symbol :in f-symbols
:with body = body
:do (setf body (subst f-symbol symbol body :test #'eq))
:finally (return body)))))
使用示例:
CL-USER> (with-symbols-from (:cffi foreign-alloc mem-aref)
(let ((a (foreign-alloc :int)))
(setf (mem-aref a :int) 1)
(mem-aref a :int)))
1
以上扩展为:
(PROGN
(LET ((A (CFFI:FOREIGN-ALLOC :INT)))
(SETF (CFFI:MEM-AREF A :INT) 1)
(CFFI:MEM-AREF A :INT)))
立即想到的问题是“你为什么要这样做?”
通常,我会简单地将包导入到需要它的(项目特定的)包中和/或构建我的项目包树,这样如果我绝对不能将包 B 导入包 A,则有一个包 A-sub导入它,导出一些函数,然后从包 A 中的其他代码调用 A-sub:function。
作为一般规则,如果你正在尝试做一些在 Common Lisp 中看起来很尴尬的事情,那么可能是时候退后一步,考虑一下你正在尝试做的事情是否是完成你想要的事情的最佳方式(在这个在这种情况下,问题可能是“是否socket-bind
从 sb-bsd-sockets 导入符号是否重要?”如果答案不是响亮的“是”,那么只需将 socket-bind 导入您的包中)。
在函数内部,不:defun
表单read
在 current*package*
中,并且其中的符号在处理任何其他(内部)之前被解析。
但是,您可以执行以下操作(未经测试且不推荐):
(defpackage #:tmp (:use cl sb-bsd-sockets))
(in-package #:tmp)
(defun old-pack::myfun ...)
(in-package old-pack) ; the package which was current before `tmp` was created
(delete-package #:tmp)
一般来说,这不是一个好主意。
将套接字代码移动到带有单独包的单独文件中,然后在其他文件中使用该包会更干净。
还有导入功能。
(import 'sb-bsd-sockets:socket-bind)
(import 'sb-bsd-sockets:socket-listen)
(socket-listen) ;; error, but found