2

我想在另一个名称很长的包中使用一些函数(例如,“sb-bsd-sockets”),我必须这样写:

(defun myfun (...)
   (sb-bsd-sockets:socket-bind ...)
   (sb-bsd-sockets:socket-listen ...)
   ...)

有没有办法导入其中一些仅在内部可用的符号myfun(没有任何性能损失)?

4

4 回答 4

4

以下是我脑海中闪现的第一件事(简单的树遍历和符号名称替换)。

应该注意的是,问题是关于导入符号的,以下内容没有这样做。它只是为您添加了丑陋的 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)))
于 2013-09-09T08:47:43.607 回答
2

立即想到的问题是“你为什么要这样做?”

通常,我会简单地将包导入到需要它的(项目特定的)包中和/或构建我的项目包树,这样如果我绝对不能将包 B 导入包 A,则有一个包 A-sub导入它,导出一些函数,然后从包 A 中的其他代码调用 A-sub:function。

作为一般规则,如果你正在尝试做一些在 Common Lisp 中看起来很尴尬的事情,那么可能是时候退后一步,考虑一下你正在尝试做的事情是否是完成你想要的事情的最佳方式(在这个在这种情况下,问题可能是“是否socket-bind从 sb-bsd-sockets 导入符号是否重要?”如果答案不是响亮的“是”,那么只需将 socket-bind 导入您的包中)。

于 2013-09-11T16:53:47.943 回答
2

在函数内部,不: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)

一般来说,这不是一个好主意。

将套接字代码移动到带有单独包的单独文件中,然后在其他文件中使用该包会更干净。

于 2013-09-08T14:29:35.780 回答
1

还有导入功能。

(import 'sb-bsd-sockets:socket-bind)
(import 'sb-bsd-sockets:socket-listen)
(socket-listen) ;; error, but found
于 2021-05-02T05:49:30.917 回答