Cierres como objetos
Parte de la sección Programación orientada a objetos del Journey de R de Coddy. Lección 17 de 57.
Ya conociste las clausuras en Lógica y flujo: 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 crea 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] 150Cada llamada a la fábrica vuelve a ejecutar su cuerpo, así 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 5Los datos son privados. balance no es un elemento de la lista, así 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] 100Los 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] 10Desafío
FácilCompleta la función 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 restablece a start y value() lo devuelve.
El código proporcionado lee el valor inicial y, 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 los de 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 proporcionado: 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 = "")
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
1Fundamentos de S3
Trabajar con archivosListas con una claseFunciones constructorasMétodos de impresión y formatoValidadores y auxiliaresRepaso: temperaturas4Encapsulación en R
Cierres como objetosEntornos como objetosFunciones de accesoProtección del estadoRepaso: parquímetro2S3 Genéricos y métodos
Genéricos y UseMethodMétodos predeterminadosMétodos para genéricos baseFundamentos de NextMethodRepaso: áreas de figuras5Clases S4
Definición de clases S4Slots y accesoComprobaciones de validezMétodos showRepaso - Catálogo de productos8Clases de referencia
Definición de clases de referenciaMétodos y actualizaciones de camposSemántica de copiaHerencia y callSuperRepaso: cola de tareas11Proyecto: Gestión de biblioteca
Libros y miembrosPréstamo de librosPractica por tu cuenta: Compilador de R online