R S4类
- S4 类的概念:S4 类是 R 语言中的一种高级数据结构,提供了具有正式定义和统一创建方式的结构,增加了代码的安全性并减少错误。
- 创建和使用 S4 类:使用
setClass()在 R 中定义 S4 类,通过new()函数创建对象,并用@运算符访问类的槽(成员变量)。 - S4 类的高级特性:可以编写自定义方法(如使用
setMethod()定义show()方法),并使用泛型函数,如isS4()来检查函数类型。
S4 类是对 S3 类的改进。它们具有正式定义的结构和创建对象的统一方式。
这为我们的代码增加了安全性,并防止我们意外犯下简单的错误。
在 R 中定义 S4 类
在 R 中,我们使用 setClass() 函数来定义一个类。
R 中的成员变量被称为槽(slots)。在定义类时,我们需要设置其名称和槽(以及槽的类别)。例如,
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 类和对象
# 创建一个带有三个成员变量的类 "Student_Info"
setClass("Employee_Info", slots=list(name="character", age="numeric", role="character"))
# 创建该类的一个对象
employee1 <- new("Employee_Info", name = "Peter", age = 21, role = "Developer")
# 调用 employee1 对象
employee1
输出
一个 "Employee_Info" 类的对象
槽 "name":
[1] "Peter"
槽 "age":
[1] 21
槽 "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 中,我们使用 @ 运算符来访问槽。例如,
# 访问 Employee_Info 类的 name 槽
employee1@name # 打印 "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")
# 访问 Employee_Info 的 name 槽
employee1@name # 打印 "Peter"
# 访问 Employee_Info 的 role 槽
employee1@role # 打印 "Developer"
输出
[1] "Peter"
[1] "Developer"
这里,
employee1@name- 访问Employee_Info的 name 插槽并打印"Peter"employee1@role- 访问Employee_Info的 role 插槽并打印"Developer"
在 R 中修改 S4 类的插槽
我们可以使用 @ 来访问和分配新值给 R 中的一个插槽。例如,
# 访问并为 role 插槽分配新值
employee1@role <- "Designer"
# 打印新插槽值
employee1@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")
# 访问并修改 Employee_Info 的 name 插槽
employee1@name <- "Jack"
# 访问并修改 Employee_Info 的 role 插槽
employee1@role <- "Designer"
# 打印 name 插槽的修改后的值
employee1@name # 打印 "Jack"
# 打印 role 插槽的修改后的值
employee1@role # 打印 "Designer"
输出
[1] "Jack"
[1] "Designer"
这里,
employee1@name <- "Jack"- 将 name 插槽的值从"Peter"更改为"Jack"。employee1@role <- "Designer"- 将 role 插槽从"Developer"更改为"Designer"。
R 中的 S4 泛型函数和方法
与 S3 类 的情况一样,S4 类的方法也属于泛型函数,而不是类本身。
使用 S4 泛型与 S3 泛型非常相似。
我们可以使用 showMethods() 函数列出所有可用的 S4 泛型函数和方法:
# 列出所有 S4 泛型方法
showMethods()
输出
Function: - (package base)
Function: != (package base)
...
...
Function: trigamma (package base)
Function: trunc (package base)
在创建了类的对象之后,当我们在交互模式下仅写下对象的名称时,它会打印对象。这是使用 S4 泛型函数 show() 完成的。
您可以在上面的列表中看到这 个函数。这个函数是 S3 print() 函数的 S4 对应物。
# 不使用 show() 调用对象
employee1
# 使用 show() 调用对象
show(employee1)
这里,在两种情况下,输出将是相同的。
示例:检查函数是否为泛型函数
isS4(print)
# 输出:[1] FALSE
isS4(show)
# 输出:[1] TRUE
这里,我们使用了 isS4() 函数来检查一个函数是否为 S4 泛型函数。
因为,
print不是 S4 泛型函数,所以函数返回FALSEshow是 S4 泛型函数,所以函数返回TRUE
在 R 中编写自己的方法
在 R 中,我们可以使用 setMethod() 函数编写自己的方法。
例如,我们可以为 show() 泛型实现我们的类方法,如下所示。
setMethod("show",
"Employee_Info",
function(obj) {
cat(obj@name, "\n")
cat(obj@age, "岁\n")
cat("角色:", 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")
# 创建自己的方法
setMethod("show",
"Employee_Info",
function(object) {
cat(object@name, "\n")
cat(object@age, "岁\n")
cat("角色:", object@role, "\n")
}
)
# 调用 employee1 对象
employee1
输出
Peter
21 岁
角色:Developer
这里,我们为 show() 泛型创建了自己的方法。我们传递了 object 作为参数。
我们使用 object 和 @ 来获取 Employee_Info 类的 name、age 和 role 属性的值。
现在这个方法将在我们写出对象名称时被调用。
所以输出将是:
Peter
21 岁
角色:Developer
而不是
一个 "Employee_Info" 类的对象
槽 "name":
[1] "Peter"
槽 "age":
[1] 21
槽 "role":
[1] "Developer"