S4 类是 S3 类的改进。它们具有正式定义的结构和创建对象的统一方式。
这增加了我们代码的安全性,并防止我们意外地犯下一些幼稚的错误。
在 R 中定义 S4 类
在 R 中,我们使用 setClass()
函数来定义一个类。
R 中的成员变量称为槽。在定义类时,我们需要设置它将拥有的名称和槽(以及槽的类)。例如,
setClass("Employee_Info", slots=list(name="character", age="numeric", role="character"))
这里,我们创建了一个名为 Employee_Info
的类,它有三个槽(成员变量):name、age 和 role。
在 R 中创建 S4 对象
在 R 中创建对象,我们使用 new()
函数。例如,
student1 <- new("Student_Info", name = "Peter", age = 21, role = "Developer")
在这里,我们通过提供类 Student_Info
的名称和 new()
中所有三个槽的值来创建名为 student1 的对象。
示例 1:R 中的 S4 类和对象
# create a class "Student_Info" with three member variables
setClass("Employee_Info", slots=list(name="character", age="numeric", role="character"))
# create an object of class
employee1 <- new("Employee_Info", name = "Peter", age = 21, role = "Developer")
# call employee1 object
employee1
输出
An object of class "Employee_Info" Slot "name": [1] "Peter" Slot "age": [1] 21 Slot "role": [1] "Developer"
这里,我们使用 setClass()
函数创建了一个名为 Employee_Info
的 S4 类。
然后我们使用 new()
函数创建了一个名为 employee1
的对象。
new("Employee_Info", name = "Peter", age = 21, role = "Developer")
这里,
name
接受"character"
值,所以我们传入了"Peter"
age
接受"numeric"
值,所以我们传入了数值 21role
接受"character"
值,所以我们传入了"Developer"
最后,我们调用了对象 employee1。
在 R 中访问 S4 类槽
在 R 中,我们使用 @
运算符访问槽。例如,
# access name slot of Employee_Info class
employee1@name # prints "Peter"
这里,我们使用 @
访问了 Employee_Info
类的 name
槽。
所以打印出 "Peter"
。
示例:访问 S4 类槽
setClass("Employee_Info", slots=list(name="character", age="numeric", role="character"))
employee1 <- new("Employee_Info", name = "Peter", age = 21, role = "Developer")
# access name slot of Employee_Info
employee1@name # prints "Peter"
# access role slot of Employee_Info
employee1@role # prints "Developer"
输出
[1] "Peter" [1] "Developer"
这里,
employee1@name
- 访问Employee_Info
的 name 槽并打印"Peter"
employee1@role
- 访问Employee_Info
的 role 槽并打印"Developer"
在 R 中修改 S4 类槽
我们可以使用 @
在 R 中访问并为槽分配新值。例如,
# access and assign new value to role slot
employee1@role <- "Designer"
# print new slot value
employee@role
这里,role 槽的值从 "Developer"
更改为 "Designer"
。
示例:修改 S4 类槽
setClass("Employee_Info", slots=list(name="character", age="numeric", role="character"))
employee1 <- new("Employee_Info", name = "Peter", age = 21, role = "Developer")
# access and modify name slot of Employee_Info
employee1@name <- "Jack"
# access and modify role slot of Employee_Info
employee1@role <- "Designer"
# print modified value for name slot
employee1@name # prints "Jack"
# print modified value for role slot
employee1@role # prints "Designer"
输出
[1] "Jack" [1] "Designer"
这里,
employee1@name <- "Jack"
- 将 name 槽的值从"Peter"
更改为"Jack"
。employee1@role <- "Designer"
- 将 role 槽的值从"Developer"
更改为"Designer"
。
R 中的 S4 泛型函数和方法
与 *S3 类*类似,S4 类的方法也属于泛型函数,而不是类本身。
使用 S4 泛型与 S3 泛型非常相似。因此,请访问 S3 泛型 以获取泛型的详细信息。
我们可以使用函数 showMethods()
列出所有可用的 S4 泛型函数和方法
# list all s4 generic methods
showMethods()
输出
Function: - (package base) Function: != (package base) ... ... Function: trigamma (package base) Function: trunc (package base)
创建类的对象后,当我们以交互模式只写入对象的名称时,它会打印对象。这是通过 S4 泛型函数 show()
完成的。
您可以在上面的列表中看到这个函数。这个函数是 S3 print()
函数的 S4 模拟。
# call object without show()
employee1
# call object with show()
show(employee1)
这里,两种情况下,输出都将相同
示例:检查函数是否为泛型函数
isS4(print)
# Output: [1] FALSE
isS4(show)
# Output: [1] TRUE
这里,我们使用了 isS4()
函数来检查函数是否为 S4 泛型函数。
因为,
print
不是 S4 泛型函数,所以函数返回FALSE
show
是 S4 泛型函数,所以函数返回TRUE
在 R 中编写自己的方法
在 R 中,我们可以使用 setMethod()
函数编写自己的方法。
例如,我们可以为 show()
泛型实现我们的类方法,如下所示。
setMethod("show",
"Employee_Info",
function(obj) {
cat(obj@name, "\n")
cat(obj@age, "years old\n")
cat("Role:", obj@role, "\n")
}
)
在这里,我们为 show()
泛型实现了我们的类方法。
现在,如果我们像以前一样在交互模式下写出对象的名称,则执行上述代码。例如,
setClass("Employee_Info", slots=list(name="character", age="numeric", role="character"))
employee1 <- new("Employee_Info", name = "Peter", age = 21, role = "Developer")
# create own method
setMethod("show",
"Employee_Info",
function(object) {
cat(object@name, "\n")
cat(object@age, "years old\n")
cat("Role:", object@role, "\n")
}
)
# call employee1 object
employee1
输出
Peter 21 years old Role: Developer
这里,我们为 show()
泛型创建了自己的方法。我们传入 object
作为参数。
我们使用 object
和 @
来获取 Employee_Info
类的 name
、age
和 role
属性的值。
现在,每当我们写入对象名称时,都会调用此方法。
所以输出将是
Peter
21 years old
Role: Developer
而不是
An object of class "Employee_Info"
Slot "name":
[1] "Peter"
Slot "age":
[1] 21
Slot "role":
[1] "Developer"