Menu
Coddy logo textTech

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] 150

Cada 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 5

Os 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] 100

Os 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] 10
challenge icon

Desafio

Fácil

Complete 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 = "")
quiz iconTeste seus conhecimentos

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

Pratique por conta própria: Compilador de R online