Menu
CoddyTech

访问器函数

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

封装意味着其他代码通过函数与对象交互,而不是直接访问对象的字段。获取器读取一个值,设置器则修改它。对于 S3 列表,设置器会返回修改后的副本:

new_member <- function(name) structure(list(name = name), class = "member")
get_name <- function(p) p$name
set_name <- function(p, value) {
  p$name <- value
  p
}
p <- new_member("ada")
p <- set_name(p, "Ada Lovelace")
print(get_name(p))

输出:

[1] "Ada Lovelace"

访问器让对象可以更改数据的存储方式,而不会破坏使用它的代码。这个温度计存储摄氏温度,并在需要时由获取器算出华氏温度,因此调用者永远看不到字段本身:

new_thermo <- function(c) structure(list(c = c), class = "thermo")
celsius <- function(t) t$c
fahrenheit <- function(t) t$c * 9 / 5 + 32
t <- new_thermo(25)
cat(celsius(t), fahrenheit(t))

输出:

25 77

R 自带的 setter(例如 names(x) <- ...)属于替换函数。名为 "name<-"、参数为 x 和 value 的函数可以让调用者写出 name(p) <- "Bo";R 会调用它,并将结果重新赋值给 p:

new_member <- function(name) structure(list(name = name), class = "member")
name <- function(p) p$name
"name<-" <- function(x, value) {
  x$name <- trimws(value)
  x
}
p <- new_member("ada")
name(p) <- "  Bo  "
print(name(p))

输出:

[1] "Bo"

闭包对象的 getter 会返回私有数据的副本。更改该副本不会改变对象,因此访问对象的唯一途径是通过对象自己的函数:

make_list <- function() {
  items <- character(0)
  list(add = function(x) items <<- c(items, x),
       get_items = function() items)
}
todo <- make_list()
todo$add("milk")
mine <- todo$get_items()
mine[1] <- "HACKED"
print(todo$get_items())

输出:

[1] "milk"
challenge icon

挑战

简单

联系人是一个 S3 类 contact 列表,包含 name 和 email 字段。请完成 Contact.R:

  • new_contact(name, email) 会存储去除首尾空格并转换为小写的电子邮件地址。
  • 实现获取函数 contact_name(x) 和 contact_email(x)。
  • 实现替换函数 "contact_email<-",它会存储去除首尾空格并转换为小写的新电子邮件地址,这样调用者就可以写 contact_email(c1) <- value。

提供的代码会读取 name,email,然后读取新的电子邮件地址,并在每次更改后打印 Ada <ada@x.com>,最后打印已存储的字段名。

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

亲手试试

source("Contact.R")

# 提供的输入输出代码:保持原样
input <- suppressWarnings(readLines(file("stdin")))
p <- strsplit(input[1], ",")[[1]]
c1 <- new_contact(p[1], p[2])
cat(contact_name(c1), " <", contact_email(c1), ">\n", sep = "")
for (value in input[-1]) {
  contact_email(c1) <- value
  cat(contact_name(c1), " <", contact_email(c1), ">\n", sep = "")
}
cat("stored fields: ", paste(names(unclass(c1)), collapse = ", "), "\n", sep = "")
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: R 在线编译器