Closures como Objetos
Parte da seção Programação Orientada a Objetos do Journey de R da Coddy. Lição 17 de 57.
Você conheceu os closures em Logic & Flow: uma função criada dentro de outra função mantém as variáveis ao seu redor. Uma fábrica de funções que retorna uma lista dessas funções cria um objeto. Suas variáveis locais são os dados do objeto, e as funções são seus 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())Saída:
[1] 150Cada chamada da fábrica executa seu corpo novamente, portanto cada objeto recebe suas próprias variáveis. Alterar uma conta não afeta a outra:
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())Saída:
101 5Os dados são privados. balance não é um elemento da lista, portanto acc$balance é NULL, e atribuir a ele apenas adiciona um elemento não relacionado. As funções na lista constituem toda a interface pública do 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())Saída:
NULL
[1] 100Os métodos podem chamar uns aos outros quando são definidos como funções locais antes que a lista seja criada. Aqui, 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())Saída:
[1] 10Desafio
FácilComplete a fábrica make_counter(start = 0) em Counter.R. Ela mantém o valor atual privado e retorna uma lista com quatro funções: increment() e decrement() alteram o valor em 1, reset() o define novamente como start, e value() o retorna.
O código fornecido lê o valor inicial, depois os comandos +, - ou reset, e imprime o valor após cada um. No final, ele imprime os nomes na lista retornada, que deve conter somente as quatro funções.
Seu código deve ficar em Counter.R. main.R contém o código fornecido de entrada/saída e não pode ser editado.
Experimente você mesmo
source("Counter.R")
# Código de entrada/saída fornecido: mantenha-o 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 lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos do S3
Trabalhando com ArquivosListas com uma ClasseFunções ConstrutorasMétodos de Impressão e FormataçãoValidadores e AuxiliaresRevisão - Temperaturas4Encapsulamento em R
Closures como ObjetosAmbientes como ObjetosFunções de AcessoProtegendo o EstadoRecapitulação - Parquímetro2Genéricos e Métodos S3
Genéricos e UseMethodMétodos padrãoMétodos para genéricos baseFundamentos de NextMethodRevisão - Áreas de formas5Classes S4
Definindo classes S4Slots e acessoVerificações de validadeMétodos showRevisão - Catálogo de produtos8Classes de Referência
Definindo Classes de ReferênciaMétodos e Atualizações de CamposSemântica de CópiaHerança e callSuperRecapitulação — Fila de Tarefas11Projeto: Gerenciamento de Biblioteca
Livros e MembrosEmpréstimo de LivrosPratique por conta própria: Compilador de R online