Menu
CoddyTech

定义引用类

本课属于 Coddy R 学习旅程的“面向对象编程”单元。第 37 课,共 57 课。

引用类(RC)是 R 中用于创建可原地更改的对象的系统,类似于 Java 或 Python。setRefClass() 用于声明包含类型化字段的类,并返回一个生成器;$new() 用于创建对象,$ 用于读取和更改对象的字段:

Account <- setRefClass("Account", fields = list(owner = "character", balance = "numeric"))
a <- Account$new(owner = "Ada", balance = 100)
a$balance <- a$balance + 50
cat(a$owner, a$balance)

输出:

Ada 150

RC 对象是一种引用,类似于环境。把它赋给另一个变量或将它传给函数都不会复制它,因此通过任何名称进行的更改,都会修改同一个对象:

Account <- setRefClass("Account", fields = list(owner = "character", balance = "numeric"))
pay_fee <- function(acc) acc$balance <- acc$balance - 5
a <- Account$new(owner = "Ada", balance = 100)
b <- a
b$balance <- 60
pay_fee(a)
cat(a$balance, b$balance)

输出:

55 55

字段有类型限制。赋予字段错误类的值会被拒绝,字段会保留原来的值:

Account <- setRefClass("Account", fields = list(owner = "character", balance = "numeric"))
a <- Account$new(owner = "Ada", balance = 100)
msg <- tryCatch({ a$balance <- "lots"; "changed" }, error = function(e) conditionMessage(e))
cat(msg, "\n")
cat(a$balance, "\n")

输出:

invalid assignment for reference class field ‘balance’, should be from class “numeric” or a subclass (was class “character”) 
100 

生成器用于描述类:Account$fields() 会列出字段及其类型。打印没有 show 方法的对象时,会列出它的字段;未赋值的字段为空:

Account <- setRefClass("Account", fields = list(owner = "character", balance = "numeric"))
print(Account$fields())
Account$new(owner = "Bo")

输出:

      owner     balance 
"character"   "numeric" 
Reference class object of class "Account"
Field "owner":
[1] "Bo"
Field "balance":
numeric(0)
challenge icon

挑战

简单

在 Book.R 中声明引用类 Book,包含字段 title 和 author(字符型),以及 pages(数值型),并保留 Book 中的生成器。然后编写 add_pages(book, n),将 n 原地加到书籍的页数上,不需要返回有用的值。

提供的代码会读取 title;author;pages,创建书籍,将它赋给第二个变量,通过第二个名称添加剩余的数字,然后输出原始书籍和字段名称。

你的代码写在 Book.R 中。main.R 包含提供的输入/输出代码,不能编辑。

亲手试试

source("Book.R")

# 提供的输入输出代码:保持原样。
input <- suppressWarnings(readLines(file("stdin")))
p <- strsplit(input[1], ";")[[1]]
b <- Book$new(title = p[1], author = p[2], pages = as.numeric(p[3]))
alias <- b
for (n in as.numeric(input[-1])) add_pages(alias, n)
cat(b$title, " by ", b$author, ": ", b$pages, " pages\n", sep = "")
cat("fields: ", paste(names(Book$fields()), collapse = ", "), "\n", sep = "")
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: R 在线编译器