S3类的最大优点是方便,但是使用S3类并不安全。例如,你可以任意修改S3类,哪怕是不合法的修改。关于S3类,可以参考R语言的S3类与泛型函数。相比而言,S4类更加安全。
我们可以用下面的方式定义一个S4类mybox并初始化一个对象:
setClass('mybox', slots = list(long = 'numeric', width = 'numeric', height = 'numeric', name = 'character') ) myBox <- new('mybox') myBox
An object of class "mybox"
Slot "long":
numeric(0)
Slot "width":
numeric(0)
Slot "height":
numeric(0)
Slot "name":
character(0)
现在我们看到,对象myBox中有一系列的slot变量(可以翻译为槽变量),其类型就是我们设置的类型。在上面初始化的代码中,我们并未对slot变量赋值。我们可以在初始化的时候赋值:
myBox <- new('mybox', long = 3, width = 4, height = 5, name = 'box1') myBox
An object of class "mybox"
Slot "long":
[1] 3
Slot "width":
[1] 4
Slot "height":
[1] 5
Slot "name":
[1] "box1"
现在,我们看到myBox对象中的slot变量已经被赋值。我们可以用下面两种方式来获得某个slot变量:
slot(myBox, 'long') myBox@long
当然,我们也可以对某个slot赋值:
myBox@long <- 100
为了显示S4类是安全的,我们故意输入错误:
myBox@longg <- 100
此时会提示错误:
Error in checkAtAssignment("mybox", "longg", "numeric") :
‘longg’ is not a slot in class “mybox”
注意,对于S3类来说,这种情况不会有任何提示。
我们可以为类mybox定一个方法volume用来计算盒子的体积。注意,因为volume这个函数之前没有存在过,我们首先需要定义这个函数本身作为泛型函数,然后再设置mybox类的方法:
setGeneric('volume', function(object) { standardGeneric('volume') } ) setMethod('volume', 'mybox', function(object) { return(object@long * object@width * object@height) } )
现在我们可以计算盒子的体积了:
volume(myBox)
[1] 60
现在我们可以总结一下S3类和S4类的区别了。
1.在定义S3类的时候,没有显式的定义过程,而定义S4类的时候需要调用函数setClass;
2.在初始化S3对象的时候,只是建立了一个list,然后设置其class属性,而初始化S4对象时需要使用函数new;
3.提取变量的符号不同,S3为@,而S4为$;
4.在应用泛型函数时,S3需要定义f.classname,而S4需要使用setMethod函数;
5.在声明泛型函数时,S3使用UseMethod(), 而S4使用setGeneric()。