Menu
Coddy logo textTech

Cierres como objetos

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

Conociste las clausuras en Logic & Flow: una función creada dentro de otra función conserva las variables que la rodean. Una fábrica de funciones que devuelve una lista de esas funciones construye un objeto. Sus variables locales son los datos del objeto, y las funciones son sus métodos:

make_account <- function(balance = 0) {
  deposit <- function(x) balance <<- balance + x
  get_balance <- function() balance
  list(deposit = deposit, get_balance = get_balance)
}
acc <- make_account(100)
acc$deposit(50)
print(acc$get_balance())

Salida:

[1] 150

Cada llamada a la fábrica vuelve a ejecutar su cuerpo, por lo que cada objeto obtiene sus propias variables. Cambiar una cuenta no afecta a la otra:

make_account <- function(balance = 0) {
  list(deposit = function(x) balance <<- balance + x,
       get_balance = function() balance)
}
ada <- make_account(100)
bo <- make_account(5)
ada$deposit(1)
cat(ada$get_balance(), bo$get_balance())

Salida:

101 5

Los datos son privados. balance no es un elemento de la lista, por lo que acc$balance es NULL y asignarle un valor solo añade un elemento no relacionado. Las funciones de la lista constituyen toda la interfaz pública del objeto:

make_account <- function(balance = 0) {
  list(get_balance = function() balance)
}
acc <- make_account(100)
print(acc$balance)
acc$balance <- 1e6
print(acc$get_balance())

Salida:

NULL
[1] 100

Los métodos pueden llamarse entre sí cuando se definen como funciones locales antes de crear la lista. Aquí add_many() reutiliza add():

make_tally <- function() {
  total <- 0
  add <- function(x) total <<- total + x
  add_many <- function(xs) for (x in xs) add(x)
  get <- function() total
  list(add = add, add_many = add_many, get = get)
}
t <- make_tally()
t$add(1)
t$add_many(c(2, 3, 4))
print(t$get())

Salida:

[1] 10
challenge icon

Desafío

Fácil

Completa la fábrica make_counter(start = 0) en Counter.R. Mantiene privado el valor actual y devuelve una lista con cuatro funciones: increment() y decrement() cambian el valor en 1, reset() lo establece de nuevo en start y value() lo devuelve.

El código proporcionado lee el valor inicial, después los comandos +, - o reset, e imprime el valor después de cada uno. Al final imprime los nombres de la lista devuelta, que deben ser únicamente las cuatro funciones.

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

Pruébalo tú mismo

source("Counter.R")

# Código de entrada/salida suministrado: déjalo tal como está
input <- suppressWarnings(readLines(file("stdin")))
counter <- make_counter(as.numeric(input[1]))
for (cmd in input[-1]) {
  if (cmd == "+") counter$increment()
  if (cmd == "-") counter$decrement()
  if (cmd == "reset") counter$reset()
  cat(cmd, " -> ", counter$value(), "\n", sep = "")
}
cat("fields visible: ", paste(sort(names(counter)), collapse = ", "), "\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