Menu
Coddy logo textTech

Семантика копирования

Часть раздела Объектно-ориентированное программирование путешествия по R на Coddy. Урок 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

identical(a, b) равно TRUE для двух имён одного и того же объекта RC и 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

Задание

Легко

Текстовый редактор хранит точки сохранения. Объявите Reference Class Document в Document.R с полем text (character) и методом 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