【问题标题】:Common Lisp: How to import symbols of other packages inside a lexical scope only?Common Lisp:如何仅在词法范围内导入其他包的符号?
【发布时间】:2013-09-08 03:03:57
【问题描述】:

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

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

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

【问题讨论】:

    标签: import common-lisp temporal


    【解决方案1】:

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

    应该注意,问题是关于导入 符号,而以下内容并没有这样做。它只是为你添加了丑陋的 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)))
    

    【讨论】:

      【解决方案2】:

      在函数内部,否:defun 形式是当前*package* 中的read,其中的符号在处理任何其他(内部)之前被解析。 p>

      但是,您可以执行以下操作(未经测试且推荐):

      (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)
      

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

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

      【讨论】:

      • 谢谢。还有一个问题:有没有办法为包使用临时昵称?
      • 您可以使用defpackage更改昵称列表。
      【解决方案3】:

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

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

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

      【讨论】:

      • hmm,我想在我的一两个函数中使用sb-bsd-sockets的一些函数,并且我不想将socket-xxx的东西暴露给我代码的其他部分以防止名称冲突.我不想要 A-sub 解决方案,因为只有一两个函数需要socket-xxx。现在我的解决方案是(defpackage #:tmp (:use #:sb-bsd-sockets #:others)),然后使用tmp::socket-xxx,最后使用(delete-package #:tmp)。这个还是不太好看。
      • @SaltyEgg 如果您最终遇到名称冲突,您始终可以在导入时隐藏这些符号。在明确需要之前,您不必扭曲自己。
      【解决方案4】:

      还有import函数。

      (import 'sb-bsd-sockets:socket-bind)
      (import 'sb-bsd-sockets:socket-listen)
      (socket-listen) ;; error, but found
      

      【讨论】:

        猜你喜欢
        • 2012-04-02
        • 2021-01-30
        • 1970-01-01
        • 2019-09-28
        • 2011-07-02
        • 2013-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多