インスタンス作成時にあるスロットの値を元に他のスロットの値を初期化したい


Tag: オブジェクトシステム(CLOS)

インスタンス作成時にあるスロットの値を元に他のスロットの値を初期化したい

initialize-instanceにafterメソッドを追加するのが一般的。

;; クラス
(defclass *time ()
  ((universal-time :initform () :initarg :universal-time :accessor universal-time)
   (sec :initform () :initarg :sec :accessor sec)
   (minute :initform () :initarg :minute :accessor minute)
   (hour :initform () :initarg :hour :accessor hour)
   (date :initform () :initarg :date :accessor date)
   (month :initform () :initarg :month :accessor month)
   (year :initform () :initarg :year :accessor year)
   (day :initform () :initarg :day :accessor day)
   (daylight-p :initform () :initarg :daylight-p :accessor daylight-p)
   (zone :initform () :initarg :zone :accessor zone)))

下記の例では、初期化時にuniversal-timeスロットの値が与えられれば、他のスロットの値を割り出して初期化する。

;; 初期化
(defmethod initialize-instance :after ((*time *time) &key)
  (with-accessors ((universal-time universal-time)
                   (sec sec)
                   (minute minute)
                   (hour hour)
                   (date date)
                   (month month)
                   (year year)
                   (day day)
                   (daylight-p daylight-p)
                   (zone zone)) *time
    (setf (values sec minute hour date month year day daylight-p zone)
          (decode-universal-time (or universal-time (get-universal-time))))))

(let ((time (make-instance '*time :universal-time 0)))
  (date time))
;=> 1