11.3 槽的属性 (Slot Properties)

传给 defclass 的第三个参数必须是一个槽定义的列表。如上例所示,最简单的槽定义是一个表示其名称的符号。在一般情况下,一个槽定义可以是一个列表,第一个是槽的名称,伴随着一个或多个属性 (property)。属性像关键字参数那样指定。

通过替一个槽定义一个访问器 (accessor),我们隐式地定义了一个可以引用到槽的函数,使我们不需要再调用 slot-value 函数。如果我们如下更新我们的 circle 类定义,

  1. (defclass circle ()
  2. ((radius :accessor circle-radius)
  3. (center :accessor circle-center)))

那我们能够分别通过 circle-radiuscircle-center 来引用槽:

  1. > (setf c (make-instance 'circle))
  2. #<CIRCLE #XC5C726>
  3. > (setf (circle-radius c) 1)
  4. 1
  5. > (circle-radius c)
  6. 1

通过指定一个 :writer 或是一个 :reader ,而不是 :accessor ,我们可以获得访问器的写入或读取行为。

要指定一个槽的缺省值,我们可以给入一个 :initform 参数。若我们想要在 make-instance 调用期间就将槽初始化,我们可以用 :initarg 定义一个参数名。 [1] 加入刚刚所说的两件事,现在我们的类定义变成:

  1. (defclass circle ()
  2. ((radius :accessor circle-radius
  3. :initarg :radius
  4. :initform 1)
  5. (center :accessor circle-center
  6. :initarg :center
  7. :initform (cons 0 0))))

现在当我们创建一个 circle 类的实例时,我们可以使用关键字参数 :initarg 给槽赋值,或是將槽的值设为 :initform 所指定的缺省值。

  1. > (setf c (make-instance 'circle :radius 3))
  2. #<CIRCLE #XC2DE0E>
  3. > (circle-radius c)
  4. 3
  5. > (circle-center c)
  6. (0 . 0)

注意 initarg 的优先级比 initform 要高。

我们可以指定某些槽是共享的 ── 也就是每个产生出来的实例,共享槽的值都会是一样的。我们通过声明槽拥有 :allocation :class 来办到此事。(另一个办法是让一个槽有 :allocation :instance ,但由于这是缺省设置,不需要特别再声明一次。)当我们在一个实例中,改变了共享槽的值,则其它实例共享槽也会获得相同的值。所以我们会想要使用共享槽来保存所有实例都有的相同属性。

举例来说,假设我们想要模拟一群成人小报 (a flock of tabloids)的行为。(译注:可以看看什么是 tabloids。)在我们的模拟中,我们想要能够表示一个事实,也就是当一家小报采用一个头条时,其它小报也会跟进的这个行为。我们可以通过让所有的实例共享一个槽来实现。若 tabloid 类别像下面这样定义,

  1. (defclass tabloid ()
  2. ((top-story :accessor tabloid-story
  3. :allocation :class)))

那么如果我们创立两家小报,无论一家的头条是什么,另一家的头条也会是一样的:

  1. > (setf daily-blab (make-instance 'tabloid)
  2. unsolicited-mail (make-instance 'tabloid))
  3. #<TABLOID #x302000EFE5BD>
  4. > (setf (tabloid-story daily-blab) 'adultery-of-senator)
  5. ADULTERY-OF-SENATOR
  6. > (tabloid-story unsolicited-mail)
  7. ADULTERY-OF-SENATOR

译注: ADULTERY-OF-SENATOR 参议员的性丑闻。

若有给入 :documentation 属性的话,用来作为 slot 的文档字符串。通过指定一个 :type ,你保证一个槽里只会有这种类型的元素。类型声明会在 13.3 节讲解。