Menu
CoddyTech

Ngữ nghĩa sao chép

Thuộc phần Lập trình hướng đối tượng trong hành trình R của Coddy. Bài học 39 trên 57.

Đối tượng S3 và S4 là các giá trị: hàm thay đổi một đối tượng chỉ thay đổi bản sao của chính nó. Đối tượng RC là các tham chiếu: đối tượng của bên gọi sẽ thay đổi. Cùng một hàm hoạt động khác nhau với hai loại này:

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)

Đầu ra:

1 2

$copy() tạo một đối tượng mới, độc lập với các giá trị trường giống hệt. Thay đổi bản sao không làm thay đổi đối tượng gốc:

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)

Đầu ra:

0 100

Một danh sách có thể chứa cùng một đối tượng RC nhiều lần. Khi thay đổi một phần tử, tất cả phần tử đều thay đổi. Hãy tạo một đối tượng mới cho mỗi phần tử nếu chúng cần độc lập:

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)

Đầu ra:

5 0

identical(a, b) trả về TRUE với hai tên của cùng một đối tượng RC, còn với một bản sao thì trả về FALSE, ngay cả khi các trường vẫn bằng nhau:

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)

Đầu ra:

TRUE FALSE TRUE
challenge icon

Thử thách

Dễ

Trình soạn thảo văn bản lưu các điểm lưu. Khai báo lớp tham chiếu (Reference Class) Document trong Document.R với thuộc tính text (kiểu chuỗi) và phương thức (method) type(s) nối s vào văn bản. Sau đó, viết checkpoint(doc), hàm này trả về một bản sao độc lập của tài liệu.

Định nghĩa có các phương thức được bọc trong suppressMessages(). Code được cung cấp bắt đầu bằng một điểm lưu, sau đó đọc các lệnh: save lưu checkpoint(doc), undo quay lại bản sao của điểm lưu gần nhất, còn mọi dòng khác sẽ được nhập vào tài liệu. Sau mỗi lệnh, code in ra văn bản và văn bản đã lưu, vì vậy điểm lưu không bao giờ được thay đổi khi bạn tiếp tục nhập.

Đặt code của bạn trong Document.R. main.R chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.

Tự làm thử

source("Document.R")

# Đoạn code đầu vào/đầu ra đã cung cấp: giữ nguyên
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 iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch R online