Menu
CoddyTech

环境作为对象

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

环境是一组带名称的值,类似于列表,可以用 new.env() 创建。不同之处在于,环境永远不会被复制:每个引用它的变量看到的都是同一个对象,因此通过一个名称进行的更改,通过其他所有名称也都能看到:

e <- new.env()
e$count <- 1
alias <- e
alias$count <- 99
print(e$count)
l <- list(count = 1)
copy <- l
copy$count <- 99
print(l$count)

输出:

[1] 99
[1] 1

接收环境的函数会更改调用方的对象。它不必返回任何内容,调用方也不会赋值接收结果:

deposit <- function(acc, x) acc$balance <- acc$balance + x
acc <- new.env()
acc$balance <- 10
deposit(acc, 5)
deposit(acc, 5)
print(acc$balance)

输出:

[1] 20

assign()、get() 和 exists() 可以处理存储在变量中的名称,ls() 会按排序后的顺序列出环境中的名称:

e <- new.env()
for (fruit in c("pear", "apple")) assign(fruit, nchar(fruit), envir = e)
print(ls(e))
print(get("pear", envir = e))
print(exists("kiwi", envir = e))

输出:

[1] "apple" "pear" 
[1] 4
[1] FALSE

带有类属性的环境是具有引用语义的 S3 对象:它的方法照常工作,修改它的函数会直接在原对象上进行修改:

new_wallet <- function(coins = 0) {
  w <- new.env()
  w$coins <- coins
  class(w) <- "wallet"
  w
}
print.wallet <- function(x, ...) {
  cat("wallet with", x$coins, "coins\n")
  invisible(x)
}
spend <- function(w, n) w$coins <- w$coins - n
w <- new_wallet(10)
spend(w, 3)
w

输出:

wallet with 7 coins
challenge icon

挑战

简单

库存是一个类为 inventory 的环境,其中有一个变量 items,它是一个带名称的数值型库存向量。完成 Inventory.R:

  • new_inventory() 创建一个环境,其中包含空的 items(使用 c() 即可)和类。
  • add_stock(inv, item, n) 将 n 加到该商品的库存中。新商品的初始库存为 0。
  • take_stock(inv, item, n) 在库存充足时扣除 n 并返回 TRUE,否则不做任何更改并返回 FALSE。
  • stock_of(inv, item) 返回库存量;商品未知时返回 0。

这些函数会直接修改库存,不会返回库存对象。提供的代码会读取命令 add apple 5 和 take apple 2,打印每条 take 命令的结果,然后按字母顺序打印所有商品。

你的代码应写在 Inventory.R 中。main.R 包含提供的输入/输出代码,不能编辑。

亲手试试

source("Inventory.R")

# 提供的输入和输出代码:保持原样
input <- suppressWarnings(readLines(file("stdin")))
inv <- new_inventory()
for (line in input) {
  p <- strsplit(line, " ")[[1]]
  n <- as.numeric(p[3])
  if (p[1] == "add") add_stock(inv, p[2], n)
  if (p[1] == "take") cat("take ", p[2], ": ", if (take_stock(inv, p[2], n)) "ok" else "not enough", "\n", sep = "")
}
for (item in sort(names(inv$items))) cat(item, ": ", stock_of(inv, item), "\n", sep = "")
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: R 在线编译器