Menu
Coddy logo textTech

Entornos como objetos

Parte de la sección Programación orientada a objetos del Journey de R de Coddy. Lección 18 de 57.

Un entorno es un conjunto de valores con nombre, como una lista, creado con new.env(). La diferencia es que un entorno nunca se copia: cada variable que hace referencia a él ve el mismo objeto, por lo que un cambio realizado a través de un nombre es visible a través de todos ellos:

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)

Salida:

[1] 99
[1] 1

Una función que recibe un entorno cambia el objeto de quien la llama. No tiene que devolver nada, y quien la llama no asigna un resultado:

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

Salida:

[1] 20

assign(), get() y exists() funcionan con un nombre almacenado en una variable, y ls() enumera los nombres de un entorno en orden alfabético:

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))

Salida:

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

An environment con un atributo de clase es un objeto S3 con semántica de referencia: sus métodos funcionan como de costumbre, y las funciones que lo modifican lo hacen en el propio objeto:

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

Salida:

wallet with 7 coins
challenge icon

Desafío

Fácil

Un inventario es un entorno de clase inventory con una variable, items, un vector numérico con nombre que contiene las existencias. Completa Inventory.R:

  • new_inventory() crea el entorno con un items vacío (c() es suficiente) y la clase.
  • add_stock(inv, item, n) añade n a las existencias del artículo, empezando desde 0 para un artículo nuevo.
  • take_stock(inv, item, n) elimina n y devuelve TRUE cuando hay suficiente; de lo contrario, no cambia nada y devuelve FALSE.
  • stock_of(inv, item) devuelve las existencias, 0 para un artículo desconocido.

Las funciones modifican el inventario directamente y no lo devuelven. El código proporcionado lee los comandos add apple 5 y take apple 2, imprime el resultado de cada operación take y, después, cada artículo en orden alfabético.

Tu código va en Inventory.R. main.R contiene el código proporcionado de entrada/salida y no se puede editar.

Pruébalo tú mismo

source("Inventory.R")

# Código de entrada/salida suministrado: déjalo como está
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 iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación orientada a objetos

Practica por tu cuenta: Compilador de R online