Common lisp 在sbcl中生成实例时抑制样式警告

Common lisp 在sbcl中生成实例时抑制样式警告,common-lisp,warnings,sbcl,clos,suppress,Common Lisp,Warnings,Sbcl,Clos,Suppress,我有两个包,每个包中定义了一个类。第二个类继承自第一个类,但有一个同名的插槽。其目的确实是覆盖该插槽 (defpackage :foo (:use :cl) (:export foo)) (in-package :foo) (defclass foo () ((s))) (defpackage :bar (:use :cl :foo) (:export bar)) (in-package :bar) (defclass bar (foo) ((s))) sbcl在我创

我有两个包,每个包中定义了一个类。第二个类继承自第一个类,但有一个同名的插槽。其目的确实是覆盖该插槽

(defpackage :foo
  (:use :cl)
  (:export foo))

(in-package :foo)

(defclass foo () ((s)))

(defpackage :bar
  (:use :cl :foo)
  (:export bar))

(in-package :bar)

(defclass bar (foo) ((s)))
sbcl在我创建bar实例时给出了一个有用的警告

然而,我希望bar类的用户能够在没有得到警告的情况下创建实例


我可以编写一个包装函数,其中包含前面代码块中的代码,但是否可以在调用make instance'bar之前抑制警告,而不抑制所有样式警告?

Common Lisp中的符号通常属于一个包。当Lisp读取器遇到一个新符号时,它将把它放在由in-package设置的当前包中,除非从其他地方导入了具有相同名称的符号。通过在包和符号名称之间放置冒号或在内部符号之间放置两个冒号,可以使用包名称写入符号

如果我们将包前缀添加到您的代码中,正如Lisp阅读器看到的那样,错误会变得很容易看到:

(cl:defpackage keyword:foo
  (keyword:use keyword:cl)
  (keyword:export cl-user::foo)) ;Makes FOO:FOO an external symbol, which will be 
                                 ; imported with the (:USE ... :FOO) below.
(cl:in-package keyword:foo)

(cl:defclass foo:foo () ((foo::s))) ;FOO::S is not exported, so it 
                                    ; is an internal symbol. It will 
                                    ; not be imported by the :USE-clause.

(cl:defpackage keyword:bar
  (keyword:use keyword:cl keyword:foo) ;Import all external symbols from CL and FOO.
  (keyword:export cl-user::bar))

(cl:in-package keyword:bar)

(cl:defclass bar:bar (foo:foo) ;FOO:FOO was imported from the other package.
  ((bar::s))) ;FOO::S (an internal symbol) wasn't imported, so a new
              ; symbol was interned in BAR.

类BAR:BAR实际上有两个插槽,FOO::S和BAR::S。插槽名称具有相同的SYMBOL-NAME,但具有不同的SYMBOL-PACKAGE。这很少是程序员想要的,因此SBCL给出了一个警告。为了解决这个问题,您应该导出FOO::S,这样在包栏中写入不合格的S将引用相同的符号。或者,您可以将插槽名称写入包限定格式,但通常不建议使用其他包的内部符号。

Common Lisp中的符号通常属于包。当Lisp读取器遇到一个新符号时,它将把它放在由in-package设置的当前包中,除非从其他地方导入了具有相同名称的符号。通过在包和符号名称之间放置冒号或在内部符号之间放置两个冒号,可以使用包名称写入符号

如果我们将包前缀添加到您的代码中,正如Lisp阅读器看到的那样,错误会变得很容易看到:

(cl:defpackage keyword:foo
  (keyword:use keyword:cl)
  (keyword:export cl-user::foo)) ;Makes FOO:FOO an external symbol, which will be 
                                 ; imported with the (:USE ... :FOO) below.
(cl:in-package keyword:foo)

(cl:defclass foo:foo () ((foo::s))) ;FOO::S is not exported, so it 
                                    ; is an internal symbol. It will 
                                    ; not be imported by the :USE-clause.

(cl:defpackage keyword:bar
  (keyword:use keyword:cl keyword:foo) ;Import all external symbols from CL and FOO.
  (keyword:export cl-user::bar))

(cl:in-package keyword:bar)

(cl:defclass bar:bar (foo:foo) ;FOO:FOO was imported from the other package.
  ((bar::s))) ;FOO::S (an internal symbol) wasn't imported, so a new
              ; symbol was interned in BAR.

类BAR:BAR实际上有两个插槽,FOO::S和BAR::S。插槽名称具有相同的SYMBOL-NAME,但具有不同的SYMBOL-PACKAGE。这很少是程序员想要的,因此SBCL给出了一个警告。为了解决这个问题,您应该导出FOO::S,这样在包栏中写入不合格的S将引用相同的符号。或者,您可以将插槽名称写在包限定的表单中,但通常不建议使用其他包的内部符号。

这里的警告似乎很有用,但如果您发现自己处于必须将其隐藏的情况下,则适当的位置应该在类终结时:

#+sbcl
(defmethod sb-mop:finalize-inheritance :around ((c (eql (find-class 'bar))))
   (handler-bind ((sb-int:simple-style-warning #'muffle-warning))
     (call-next-method)))
创建新实例时出错,但当我测试代码时,在REPL中定义类时发出错误信号。这是在类终结期间发出错误信号的线索,必须在defclass之后完成,但不一定在分配第一个实例之前立即完成。见:

调用finalize继承的确切点取决于类元对象的类;对于标准类,它在定义类的所有超类之后的某个时间调用,但不晚于由allocate instance分配类的第一个实例


这一警告在这里似乎很有用,但如果你发现自己处于一种不得不压制它的境地,那么适当的地方应该是在课程结束之前:

#+sbcl
(defmethod sb-mop:finalize-inheritance :around ((c (eql (find-class 'bar))))
   (handler-bind ((sb-int:simple-style-warning #'muffle-warning))
     (call-next-method)))
创建新实例时出错,但当我测试代码时,在REPL中定义类时发出错误信号。这是在类终结期间发出错误信号的线索,必须在defclass之后完成,但不一定在分配第一个实例之前立即完成。见:

调用finalize继承的确切点取决于类元对象的类;对于标准类,它在定义类的所有超类之后的某个时间调用,但不晚于由allocate instance分配类的第一个实例


如果要覆盖插槽,则必须从其他包导入名称或使用包限定名称。现在,您有两个插槽,FOO::S和BAR::S.@jkiiski-Doh!接得好,谢谢。这正是警告的内容-请回答。如果要覆盖插槽,必须从其他包导入名称或使用包限定名称。现在,您有两个插槽,FOO::S和BAR::S.@jkiiski-Doh!接得好,谢谢。这正是警告的内容-请回答一下。