(本文是AdvancedR的S3章读书笔记)
S3类是R语言中最基础的类设计,是居于object+attribute的方式构造的。
构造
方法 | 代码 |
---|---|
一步构造 | o1 <- structure(data, class = "ClassA") |
显式设置 | o1 <- data; class(o1) <- "ClassA" |
和类相关的几个函数:
typeof(obj)
attributes(obj)
class(obj)/unclass(obj)
sloop::s3_dispatch()
sloop::s3_get_method()
inherits(obj, "classname")
泛函数和类方法 Generic & Methods
定义泛函数
# 定义一个新的泛函数
new_generic_func <- function(x, ...) {
UseMethod("new_generic_func")
}
# 定义泛函数缺省的方法(method)
new_generic_func.default <- function(x, ...) {
# 缺省实现
}
# 定义泛函数指定类的方法(method)
new_generic_func.ClassA <- function(x, ...) {
# ClassA对应的实现
}
UseMethod(generic, object)
第一个参数是泛函数的名字(字符串),第二个参数的传入的对象,function传入的第一个参数。
methods(generic.function, class)
generic.function和class参数两者择一,可以查看实现了该泛函数的所有类,也可以查看一个class定义了哪些泛函数。
sloop::s3_methods_generic()
和sloop::s3_methods_class()
显示更详细的信息。
继承
S3的继承比较简单,通过如下机制是实现:
- class属性是个字符串向量,按子类到父类从左到右依次排列。假如需要表示继承父类,取得父类的class向量后,在最前面添加子类的class名字。
- method调用,根据class向量,从左到右查找,直到找到泛函数的定义。
- 调用
NextMethod()
可以把method调用deletate到另一个泛函数。
泛函数查找机制
当调用一个泛函数时,根据传入的对象的类型去查找对应定义的函数。比如传入一个对象,其class是list,则去查找new_generic_func.list的函数。若找到了,则把参数传入直接调用; 若没有则查找new_generic_func.default函数;没有default函数则抛出错误。
对于继承类,顺着子类到父类的顺序回溯查找,直到找到default为止(假如有定义default函数)
sloop::s3_dispatch()
可以清楚的显示泛函数调用到底dispatch给了哪个对应类定义的泛函数。其中前导符号的意思是:
=>
method exists and is found byUseMethod()
.->
method exists and is used byNextMethod()
.*
method exists but is not used.- Nothing (and greyed out in console): method does not exist.
NextMethod()
调用NextMethod()
, 触发泛函数往后查找一个定义了的实现,把参数传到该实现函数,并返回调用值。
# NextMethod定义
NextMethod(generic = NULL, object = NULL, ...)
generic指定了查找的generic,object指定了delegate的对象。
如果generic为NULL,则是调用NextMethod的函数名;
如果object为NULL,则查找参数的第一个对象起始的generic的下一个定义了的generic。