R S4 类

S4 类是 S3 类的改进。它们具有正式定义的结构和创建对象的统一方式。

这增加了我们代码的安全性,并防止我们意外地犯下一些幼稚的错误。


在 R 中定义 S4 类

在 R 中,我们使用 setClass() 函数来定义一个类。

R 中的成员变量称为槽。在定义类时,我们需要设置它将拥有的名称和槽(以及槽的类)。例如,

setClass("Employee_Info", slots=list(name="character", age="numeric", role="character"))

这里,我们创建了一个名为 Employee_Info 的类,它有三个槽(成员变量):nameagerole


在 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" 值,所以我们传入了数值 21
  • role 接受 "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 类的 nameagerole 属性的值。

现在,每当我们写入对象名称时,都会调用此方法。

所以输出将是

Peter 
21 years old
Role: Developer

而不是

An object of class "Employee_Info"
Slot "name":
[1] "Peter"

Slot "age":
[1] 21

Slot "role":
[1] "Developer"

你觉得这篇文章有帮助吗?

我们的高级学习平台,凭借十多年的经验和数千条反馈创建。

以前所未有的方式学习和提高您的编程技能。

试用 Programiz PRO
  • 交互式课程
  • 证书
  • AI 帮助
  • 2000+ 挑战