插槽与访问
本课属于 Coddy R 学习旅程的“面向对象编程”单元。第 23 课,共 57 课。
obj@slot <- value 会修改一个槽。和 S3 对象一样,S4 对象也是值:修改对象的函数会操作它自己的副本,并返回这个副本:
setClass("Person", slots = c(name = "character", age = "numeric"))
birthday <- function(p) {
p@age <- p@age + 1
p
}
ada <- new("Person", name = "Ada", age = 36)
older <- birthday(ada)
cat(ada@age, older@age)输出:
36 37slot(obj, "name") 与 @ 的作用相同,只是把槽名称作为字符串传入,因此你可以使用存储在变量中的名称。slotNames() 会列出类或对象的槽:
setClass("Person", slots = c(name = "character", age = "numeric"))
ada <- new("Person", name = "Ada", age = 36)
for (s in slotNames(ada)) cat(s, "=", format(slot(ada, s)), "\n")
slot(ada, "age") <- 37
print(ada@age)输出:
name = Ada
age = 36
[1] 37每次赋值都会检查声明的类型,不只是 new()。如果值的类型不正确,赋值会被拒绝,对象会保留原来的值:
setClass("Person", slots = c(name = "character", age = "numeric"))
ada <- new("Person", name = "Ada", age = 36)
ada@age <- "old"输出:
Error in (function (cl, name, valueClass) :
assignment of an object of class “character” is not valid for @‘age’ in an object of class “Person”; is(value, "numeric") is not TRUE
Execution haltedgetSlots()会返回每个槽位名称及其声明的类型,这样代码就能将文本输入转换为槽位所需的类型:
setClass("Person", slots = c(name = "character", age = "numeric"))
types <- getSlots("Person")
print(types)
value <- "40"
if (types[["age"]] == "numeric") value <- as.numeric(value)
print(value + 1)输出:
name age
"character" "numeric"
[1] 41挑战
简单Profile 类位于 Profile.R 中,包含 name 和 city(字符型)以及 age(数值型)这些槽。请完成两个函数:
- 如果字段不是槽,
update_profile(p, field, value)会停止并显示no field email(使用call. = FALSE);否则,如果槽是数值型,就用as.numeric()转换文本value,再用slot()设置槽,并返回修改后的配置文件对象。 profile_lines(p)按槽的顺序,每个槽返回一行:name: Ada。
提供的代码会读取一个姓名,然后读取类似 city=Paris 或 age=36 的行,逐行应用这些内容,并打印配置文件对象的各行。
请在 Profile.R 中编写代码。main.R 包含提供的输入/输出代码,不能编辑。
亲手试试
source("Profile.R")
# 提供的输入输出代码:保持原样。
input <- suppressWarnings(readLines(file("stdin")))
p <- new("Profile", name = input[1], city = "unknown", age = 0)
for (line in input[-1]) {
kv <- strsplit(line, "=")[[1]]
p <- tryCatch(update_profile(p, kv[1], kv[2]), error = function(e) {
cat("error: ", conditionMessage(e), "\n", sep = "")
p
})
}
for (l in profile_lines(p)) cat(l, "\n", sep = "")
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: R 在线编译器