Использование замыкания для генерации привязки R6

Я использую активные привязки в классе R6, чтобы проверить значения перед назначением для полей. Я думал, что смогу использовать замыкание для генерации привязок, как показано ниже, но это не работает.

Привязка не оценивается так, как я ожидаю (вообще?), Потому что ошибка показывает закрытие name аргумент. Что мне не хватает?

library(R6)
library(pryr)

# pass a field name to create its binding 
generate_binding <- function(name) {
  function(value) {
    if (!missing(value) && length(value) > 0) {
      private$name <- value
    } 
    private$name
  }
}

bind_x = generate_binding(x_)
# created as intended:
unenclose(bind_x)
# function (value) 
# {
#     if (!missing(value) && length(value) > 0) {
#         private$x_ <- value
#     }
#     private$x_
# }

MyClass <- R6::R6Class("MyClass",
  private = list(
    x_ = NULL
  ),
  active = list(
    x = bind_x
  ),
)

my_class_instance <- MyClass$new()
my_class_instance$x <- "foo"
# Error in private$name <- value :
#   cannot add bindings to a locked environment

1 ответ

Решение

Я думаю, вы неправильно понимаете, как работают крышки. unenclose здесь красная сельдь (так как на самом деле она не показывает, как выглядит крышка). Закрытие содержит заявление private$name <- value - не содержит утверждения private$x_ <- value,

Обычным решением этой проблемы было бы переписать замыкание так, чтобы неоцененное name аргумент отбрасывается в его строковое представление, а затем используется для подмножества private среда (private[[name]] <- value). Однако здесь это не работает, поскольку активные привязки R6 лишают замыкания окружающей их среды.

Это где unenclose приходит тогда:

MyClass <- R6::R6Class("MyClass",
  private = list(
    x_ = NULL
  ),
  active = list(
    x = pryr::unenclose(bind_x)
  ),
)
Другие вопросы по тегам