Menu
CoddyTech

复制语义

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

S3 和 S4 对象是值:修改它们的函数只会改变自己的副本。RC 对象是引用:调用者的对象会改变。同一个函数对这两种对象的行为不同:

setClass("S4Box", slots = c(n = "numeric"))
RCBox <- setRefClass("RCBox", fields = list(n = "numeric"))
bump_s4 <- function(b) { b@n <- b@n + 1; invisible(b) }
bump_rc <- function(b) b$n <- b$n + 1
v <- new("S4Box", n = 1)
r <- RCBox$new(n = 1)
bump_s4(v)
bump_rc(r)
cat(v@n, r$n)

输出:

1 2

$copy() 会创建一个字段值相同的独立新对象。修改副本不会影响原对象:

Account <- setRefClass("Account", fields = list(balance = "numeric"))
a <- Account$new(balance = 100)
alias <- a
backup <- a$copy()
alias$balance <- 0
cat(a$balance, backup$balance)

输出:

0 100

一个列表可以多次保存同一个 RC 对象。更改其中一个元素会导致所有元素都发生变化。如果需要让元素彼此独立,就要为每个元素创建一个新对象:

Counter <- setRefClass("Counter", fields = list(n = "numeric"))
one <- Counter$new(n = 0)
same <- list(one, one, one)
same[[1]]$n <- 5
fresh <- lapply(1:3, function(i) Counter$new(n = 0))
fresh[[1]]$n <- 5
cat(same[[3]]$n, fresh[[3]]$n)

输出:

5 0

对于同一个 RC 对象的两个名称,identical(a, b) 的结果是 TRUE;对于副本,结果是 FALSE,即使字段仍然相等:

Account <- setRefClass("Account", fields = list(balance = "numeric"))
a <- Account$new(balance = 100)
b <- a
c2 <- a$copy()
cat(identical(a, b), identical(a, c2), c2$balance == a$balance)

输出:

TRUE FALSE TRUE
challenge icon

挑战

简单

文本编辑器会保留保存点。在 Document.R 中声明引用类 Document,并添加字段 text(字符类型)和方法 type(s),将 s 追加到文本中。然后编写 checkpoint(doc),返回文档的独立副本。

包含方法的定义由 suppressMessages() 包裹。提供的代码会先创建一个保存点,然后读取命令:save 会保存 checkpoint(doc),undo 会回到上一个保存点的副本,其他任何行都会被输入。每条命令执行后,代码都会打印文本和已保存的文本,因此继续输入时,保存点绝不能改变。

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

亲手试试

source("Document.R")

# 提供的输入输出代码:保持原样
input <- suppressWarnings(readLines(file("stdin")))
doc <- Document$new(text = "")
saved <- checkpoint(doc)
for (cmd in input) {
  if (cmd == "save") {
    saved <- checkpoint(doc)
  } else if (cmd == "undo") {
    doc <- checkpoint(saved)
  } else {
    doc$type(cmd)
  }
  cat(cmd, " -> [", doc$text, "] saved [", saved$text, "]\n", sep = "")
}
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: R 在线编译器