Замыкания как объекты
Часть раздела Объектно-ориентированное программирование путешествия по R на Coddy. Урок 17 из 57.
Вы познакомились с замыканиями в разделе «Логика и поток выполнения»: функция, созданная внутри другой функции, сохраняет доступ к окружающим её переменным. Фабрика функций, которая возвращает список таких функций, создаёт объект. Её локальные переменные — это данные объекта, а функции — его методы:
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())Результат:
[1] 150Каждый вызов фабрики снова выполняет её тело, поэтому каждый объект получает свои собственные переменные. Изменение одного счёта не затрагивает другой:
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())Результат:
101 5Данные являются приватными. balance не является элементом списка, поэтому acc$balance имеет значение NULL, а присваивание ему лишь добавляет несвязанный элемент. Функции в списке составляют весь публичный интерфейс объекта:
make_account <- function(balance = 0) {
list(get_balance = function() balance)
}
acc <- make_account(100)
print(acc$balance)
acc$balance <- 1e6
print(acc$get_balance())Вывод:
NULL
[1] 100Методы могут вызывать друг друга, если они определены как локальные функции до создания списка. Здесь add_many() повторно использует 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())Вывод:
[1] 10Задание
ЛегкоЗавершите фабрику make_counter(start = 0) в Counter.R. Она хранит текущее значение приватным и возвращает список с четырьмя функциями: increment() и decrement() изменяют значение на 1, reset() устанавливает его обратно в start, а value() возвращает его.
Предоставленный код считывает начальное значение, затем команды +, - или reset и выводит значение после каждой из них. В конце он выводит имена в возвращённом списке, в котором должны находиться только четыре функции.
Ваш код должен находиться в Counter.R. В main.R содержится предоставленный код ввода/вывода, и его нельзя редактировать.
Попробуйте сами
source("Counter.R")
# Предоставленный код ввода/вывода: оставьте его как есть
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 = "")
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы S3
Работа с файламиСписки с классомФункции-конструкторыМетоды print и formatВалидаторы и вспомогательные функцииПовторение — температуры4Инкапсуляция в R
Замыкания как объектыОкружения как объектыФункции доступаЗащита состоянияПовторение — парковочный счётчик7S4 Наследование
Расширение с помощью containscallNextMethodВиртуальные классыПроверка типов с помощью is()Повторение — смотритель зоопарка10Шаблоны проектирования, часть 2
Шаблон «Декоратор»Шаблон «Строитель»Шаблон «Состояние»Шаблон «Итератор»2Обобщённые функции и методы S3
Обобщённые функции и UseMethodМетоды по умолчаниюМетоды для базовых обобщённых функцийОсновы NextMethodПовторение — площади фигур5Классы S4
Определение классов S4Слоты и доступПроверка корректностиМетоды showПовторение — каталог товаров8Ссылочные классы
Определение ссылочных классовМетоды и обновление полейСемантика копированияНаследование и callSuperПовторение — очередь задач11Проект: Управление библиотекой
Книги и читателиВыдача книг3Наследование S3
Векторы классовПорядок поиска методовРасширение с помощью NextMethodПроверка с помощью inherits()Повторение — расчёт зарплаты сотрудниковПотренируйтесь самостоятельно: Онлайн-компилятор R