假设有以下定义:
#+BEGIN_SRC emacs-lisp :results output :async
(defclass person ()
((name :initarg :name)
(age :initarg :age
:initform 0)))
(defmethod person-info ((p person))
(princ (format "name: %s, age: %s\n"
(oref p name)
(oref p age))))
(setq joe (person :name "Joe"
:age -1))
(person-info joe)
#+END_SRC
#+RESULTS:
: name: Joe, age: -1
如何避免 age
设置不合理的初始值?
LdBeth
2018 年10 月 31 日 18:25
2
(cl-deftype age () '(satisfies (lambda (x) (>= x 0))))
;; This works better in particular case.
(cl-deftype age () '(integer 0))
(defclass foo ()
((x :type age :initarg :x)))
;; Or straightforwardly
(defclass foo ()
((x :type (integer 0) :initarg :x)))
;; `make-instance' is more idiomatic in CL, but `foo' would also work (Emacs Lisp only)
(make-instance 'foo :x 0)
;; => #s#s(eieio-class ...
(make-instance 'foo :x -1)
;; Lisp error: (invalid-slot-type foo x age -1)
;; Or just
(cl-check-type -1 age)
;; Lisp error: (wrong-type-argument age -1 -1)
http://www.lispworks.com/documentation/lw50/CLHS/Body/m_deftp.htm#deftype
http://www.lispworks.com/documentation/lw50/CLHS/Body/m_defcla.htm#defclass
值得注意的是不是所有 CLOS 实現都会把 :type
當回事兒,不過至少 eieio 是会做类型檢查的,尽管不是完整的 CLOS。
3 个赞
听起来各方似乎意见不太统一,就怕 eieio 哪天也认为 :type
是个鸡肋。
感觉 defstruct
更像是 class,有 :constructor
,也能“继承”。
好混乱。
APPENDED 2018-11-01 18.16.44
访问 struct 的成员可以通过 (<struct-name>-<member-name> <instance>)
,而 class 有 :accessor
可以任意更改这个函数名,可能有时候会比较便利,但我觉得还是 struct 省事:
#+BEGIN_SRC emacs-lisp :results value :async
(require 'cl)
(defstruct bar
c)
(bar-c (make-bar :c 3))
#+END_SRC
#+RESULTS:
: 3
#+BEGIN_SRC emacs-lisp :results value :async
(require 'eieio)
(defclass qux ()
((d :initarg :d
:accessor get-d)))
(get-d (make-instance 'qux :d 4))
#+END_SRC
#+RESULTS:
: 4
1 个赞
twlz0ne:
感觉 defstruct
更像是 class
defstruct
不能多重继承。自然也沒有 method combination。
:accessor
的作用在于它定义的是个 generic function:
(defclass a () ((x :accessor age :initform 1)))
(defclass b () ((y :accessor age :initform 'z)))
(age (make-instance 'a))
; => 1
(age (make-instance 'b))
; => z
沒有一定項目規模自然难以体会用 OOP 的好处。
2 个赞
Flavor 反而没啥实用意义,主要也就历史指导意义,毕竟已经被废弃了。
大部分设计都能在 CLtL2 找到,关于 CLOS 的还有 The Art of Metaobject Protocol
实在感兴趣的话 Lisp Machine Manual 提到了 defstruct 的继承功能和 Flavor 的对比。
flavor挺有意思的。倒不是说为了实用才看。感谢。smalltalk的设计和CLOS区别大吗?(我不了解)有时间我想学malltalk感受一下,有什么建议吗?
CLOS 是参照 Smalltalk (以及 Flavor 和 Common LOOPS)设计的,本质区别不大,主要也就 Generic function 和 Message passing 的区别。Smalltalk 的书只知道有个 blue book。说实话个人觉得 Maude 更有趣些,它用的是基于 包结构的 OOP,和 Ocaml 以及 Ada 类似。
1 个赞