您如何在Lisp中表达以下Java代码?
class Foo {
private String s;
public Foo(String s) {
this.s = s;
}
}
class Bar extends Foo {
public Bar(int i) {
super(Integer.toString(i));
}
}
在Lisp中,make-instance
或initialize-instance
是构造函数的等价物吗?如果是,你如何调用超类构造函数?
答案 0 :(得分:14)
在方法中使用CALL-NEXT-METHOD
来调用下一个。
通常只需使用标准方法组合工具,并为:BEFORE
编写:AFTER
,:AROUND
或INITIALIZE-INSTANCE
方法。
一种方式:
(defclass foo ()
((s :type string :initarg :s)))
(defclass bar (foo) ())
(defmethod initialize-instance :around ((b bar) &key i)
(call-next-method b :s (princ-to-string i)))
示例:
CL-USER 17 > (make-instance 'bar :i 10)
#<BAR 402000B95B>
CL-USER 18 > (describe *)
#<BAR 4130439703> is a BAR
S "10"
请注意,我已调用CALL-NEXT-METHOD
而不更改其调度的参数。我刚刚更改了&key
initarg参数。
答案 1 :(得分:3)
这是Rainier的一个例子,它增加了一个小小的变化: 通过约束槽值来进行特化(子类化),至少在 施工时间。考虑用于二维矩形的类 m-box :
(defclass m-box ()
((left :accessor m-box-left :initform 0 :type integer :initarg :left )
(top :accessor m-box-top :initform 0 :type integer :initarg :top )
(width :accessor m-box-width :initform 0 :type integer :initarg :width )
(height :accessor m-box-height :initform 0 :type integer :initarg :height)))
我们可以这样试试:
(describe (make-instance 'm-box :left 42 :top -39 :width 5 :height 11))
: #<M-BOX {10047A8F83}>
: [standard-object]
:
: Slots with :INSTANCE allocation:
: LEFT = 42
: TOP = -39
: WIDTH = 5
: HEIGHT = 11
现在考虑一个子类或专门化:让 m-block 成为一个m-box 单位宽度和高度。我们将 initialize-instance 方法设置为通过 左和顶部的值,但不是 width 和 height :
(defclass m-block (m-box) ())
(defmethod initialize-instance
:around
((mb m-block)
&key (left 0) (top 0))
(call-next-method mb :left left :top top :width 1 :height 1))
我们可以按如下方式创建 m-block 的实例:
(describe (make-instance 'm-block :left 17 :top -34 :width 5 :height 11))
: #<M-BLOCK {10049C0CC3}>
: [standard-object]
:
: Slots with :INSTANCE allocation:
: LEFT = 17
: TOP = -34
: WIDTH = 1
: HEIGHT = 1
构造函数不阻止用户尝试设置 width 和 height , 就像它对一些不存在的插槽一样:
(describe (make-instance 'm-block :left 17 :top -34 :plugh 2345))
Invalid initialization argument:
:PLUGH
in call for class #<STANDARD-CLASS COMMON-LISP-USER::M-BLOCK>.
[Condition of type SB-PCL::INITARG-ERROR]
但构造函数 用1来纠正用户的无效输入。
您可能希望通过调用error
来使模型更加无懈可击
用户尝试输入无效的宽度或高度:
(defclass m-block (m-box) ())
(defmethod initialize-instance
:around
((mb m-block)
&key (left 0) (top 0) (width 1) (height 1))
(when (or (/= 1 width) (/= 1 height))
(error "an m-block must have unit width and height"))
(call-next-method mb :left left :top top :width 1 :height 1))
拒绝用户的以下尝试:
(describe (make-instance 'm-block :left 17 :top -34 :width 5 :height 11))
an m-block must have unit width and height
[Condition of type SIMPLE-ERROR]
但是,这个也证明了身高的违约行为,通过了:
(describe (make-instance 'm-block :left 17 :top -34 :width 1))
: #<M-BLOCK {1005377983}>
: [standard-object]
:
: Slots with :INSTANCE allocation:
: LEFT = 17
: TOP = -34
: WIDTH = 1
: HEIGHT = 1
此示例允许用户之后setf
宽度或高度。我不
知道如何在子类的实例中创建宽度和高度只读
而不是超类的实例。