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 泛型函数,所以函数返回FALSE
show
是 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"