Menu
CoddyTech

插槽与访问

本课属于 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 37

slot(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 halted

getSlots()会返回每个槽位名称及其声明的类型,这样代码就能将文本输入转换为槽位所需的类型:

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
challenge icon

挑战

简单

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 = "")
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: R 在线编译器