R 引用类

R 中的引用类与我们在 C++、Java、Python 等常用语言中看到的面向对象编程相似。

S3S4 类不同,方法属于类而不是泛函。引用类在内部实现为 S4 类,并添加了一个环境。


如何定义引用类?

定义引用类类似于定义 S4 类。我们使用 setRefClass() 函数而不是 setClass()

> setRefClass("student")

如果定义了成员变量,则需要将其包含在类定义中。引用类的成员变量称为字段(类似于 S4 类中的插槽)。

以下是定义一个名为 student 的类,其中包含 3 个字段:nameageGPA 的示例。

> setRefClass("student", fields = list(name = "character", age = "numeric", GPA = "numeric"))

如何创建引用对象?

setRefClass() 函数返回一个生成器函数,用于创建该类的对象。

> student <- setRefClass("student",
    fields = list(name = "character", age = "numeric", GPA = "numeric"))
> # now student() is our generator function which can be used to create new objects

> s <- student(name = "John", age = 21, GPA = 3.5)

> s
Reference class object of class "student"
Field "name":
[1] "John"
Field "age":
[1] 21
Field "GPA":
[1] 3.5

如何访问和修改字段?

可以使用 $ 运算符访问对象的字段。

> s$name
[1] "John"

> s$age
[1] 21

> s$GPA
[1] 3.5

同样,可以通过重新赋值来修改它。

> s$name <- "Paul"

> s
Reference class object of class "student"
Field "name":
[1] "Paul"
Field "age":
[1] 21
Field "GPA":
[1] 3.5

警告提示

在 R 编程中,对象在赋值给新变量或传递给函数时会被复制(按值传递)。例如。

> # create list a and assign to b
> a <- list("x" = 1, "y" = 2)
> b <- a

> # modify b
> b$y = 3

> # a remains unaffected
> a
$x
[1] 1

$y
[1] 2

> # only b is modified
> b
$x
[1] 1

$y
[1] 3

但引用对象的情况并非如此。只有一个副本存在,所有变量都引用同一个副本。因此得名为引用。

> # create reference object a and assign to b
> a <- student(name = "John", age = 21, GPA = 3.5)
> b <- a

> # modify b
> b$name <- "Paul"

> # a and b both are modified
> a
Reference class object of class "student"
Field "name":
[1] "Paul"
Field "age":
[1] 21
Field "GPA":
[1] 3.5

> b
Reference class object of class "student"
Field "name":
[1] "Paul"
Field "age":
[1] 21
Field "GPA":
[1] 3.5

这可能会导致值发生一些不必要的更改,并成为奇怪错误的根源。我们在处理引用对象时需要牢记这一点。要创建副本,我们可以使用提供的 copy() 方法。

> # create reference object a and assign a’s copy to b
> a <- student(name = "John", age = 21, GPA = 3.5)
> b <- a$copy()

> # modify b
> b$name <- "Paul"

> # a remains unaffected
> a
Reference class object of class "student"
Field "name":
[1] "John"
Field "age":
[1] 21
Field "GPA":
[1] 3.5

> # only b is modified
> b
Reference class object of class "student"
Field "name":
[1] "Paul"
Field "age":
[1] 21
Field "GPA":
[1] 3.5

引用方法

方法是为引用类定义的,不属于 S3 和 S4 类中的泛函。

所有引用类都预定义了一些方法,因为它们都继承自超类 envRefClass

> student
Generator for class "student":

Class fields:
                                    
Name:       name       age       GPA
Class: character   numeric   numeric

 Class Methods:  
    "callSuper", "copy", "export", "field", "getClass", "getRefClass", 
"import", "initFields", "show", "trace", "untrace", "usingMethods"


 Reference Superclasses:  
    "envRefClass"

我们可以在上面的列表中看到像 copy()field()show() 这样的类方法。我们可以为类创建自己的方法。

这可以在类定义期间完成,方法是将函数定义列表传递给 setRefClass()methods 参数。

student <- setRefClass("student",
  fields = list(name = "character", age = "numeric", GPA = "numeric"),
  methods = list(
    inc_age = function(x) {
      age <<- age + x
    },
    dec_age = function(x) {
      age <<- age - x
    }
  )
)

在我们代码的以上部分,我们定义了两个名为 inc_age()dec_age() 的方法。这两个方法修改了 age 字段。

请注意,由于 age 不在方法的局部环境中,我们必须使用非局部赋值运算符 <<-。这一点很重要。

使用简单的赋值运算符 <- 会创建一个名为 age 的局部变量,这并非我们想要的。在这种情况下,R 会发出警告。

这是一个我们使用上述定义方法的示例运行。

> s <- student(name = "John", age = 21, GPA = 3.5)

> s$inc_age(5)
> s$age
[1] 26

> s$dec_age(10)
> s$age
[1] 16
你觉得这篇文章有帮助吗?

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

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

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